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
package/src/gobject.cc
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
#include <string.h>
|
|
3
3
|
|
|
4
|
+
#include <vector>
|
|
5
|
+
|
|
4
6
|
#include "boxed.h"
|
|
5
7
|
#include "callback.h"
|
|
6
8
|
#include "closure.h"
|
|
@@ -33,6 +35,16 @@ namespace GNodeJS {
|
|
|
33
35
|
// Our base template for all GObjects
|
|
34
36
|
static Nan::Persistent<FunctionTemplate> baseTemplate;
|
|
35
37
|
|
|
38
|
+
// JS callback (registerClass) invoked to lazily register an unregistered JS
|
|
39
|
+
// subclass the first time it is constructed. Installed via SetLazyClassRegister,
|
|
40
|
+
// this makes registerClass() optional. Empty until JS installs it.
|
|
41
|
+
static Nan::Persistent<Function> lazyClassRegister;
|
|
42
|
+
|
|
43
|
+
// JS callback invoked the first time a private/non-introspectable concrete type
|
|
44
|
+
// (eg GLocalFile) is wrapped, to mix its implemented interfaces' methods into
|
|
45
|
+
// the class prototype. Installed via SetInterfaceMethodsApplier. See issue #441.
|
|
46
|
+
static Nan::Persistent<Function> interfaceMethodsApplier;
|
|
47
|
+
|
|
36
48
|
|
|
37
49
|
static MaybeLocal<FunctionTemplate> GetClassTemplate(GType gtype);
|
|
38
50
|
static MaybeLocal<Function> GetClass(GType gtype);
|
|
@@ -163,7 +175,7 @@ static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_d
|
|
|
163
175
|
}
|
|
164
176
|
|
|
165
177
|
static void AssociateGObject(Local<Object> object, GObject *gobject, GType gtype) {
|
|
166
|
-
object
|
|
178
|
+
Nan::SetInternalFieldPointer(object, 0, gobject);
|
|
167
179
|
|
|
168
180
|
SET_OBJECT_GTYPE(object, gtype);
|
|
169
181
|
|
|
@@ -219,11 +231,40 @@ static void GObjectConstructor(const FunctionCallbackInfo<Value> &info) {
|
|
|
219
231
|
|
|
220
232
|
/* User code calling `new Gtk.Widget({ ... })` */
|
|
221
233
|
|
|
234
|
+
// Nan provides Nan::SetPrototype but no GetPrototype wrapper, and V8 14
|
|
235
|
+
// renamed Object::GetPrototype() to GetPrototypeV2().
|
|
236
|
+
#if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >= 14
|
|
237
|
+
Local<Object> proto = Nan::To<Object>(self->GetPrototypeV2()).ToLocalChecked();
|
|
238
|
+
#else
|
|
239
|
+
Local<Object> proto = Nan::To<Object>(self->GetPrototype()).ToLocalChecked();
|
|
240
|
+
#endif
|
|
241
|
+
|
|
242
|
+
/* A JS subclass (`class Foo extends Gtk.Widget {}`) that was never passed to
|
|
243
|
+
* registerClass() owns no GType: `__gtype__` is only *inherited* from its
|
|
244
|
+
* nearest registered ancestor, so constructing it as-is would silently
|
|
245
|
+
* instantiate that ancestor — losing the subtype and any vfunc overrides.
|
|
246
|
+
* Detect the missing *own* property and register the subclass on demand,
|
|
247
|
+
* which is what makes registerClass() optional. The JS callback installs an
|
|
248
|
+
* own `__gtype__` on `proto`, so the lookup below resolves to the
|
|
249
|
+
* freshly-registered subtype. */
|
|
250
|
+
if (!lazyClassRegister.IsEmpty()
|
|
251
|
+
&& !Nan::HasOwnProperty(proto, UTF8("__gtype__")).FromMaybe(true)) {
|
|
252
|
+
Local<Function> registerFn = Nan::New<Function>(lazyClassRegister);
|
|
253
|
+
Local<Value> klass = Nan::Get(proto, UTF8("constructor")).ToLocalChecked();
|
|
254
|
+
Local<Value> argv[] = { klass };
|
|
255
|
+
Nan::TryCatch tryCatch;
|
|
256
|
+
Nan::Call(registerFn, Nan::GetCurrentContext()->Global(), 1, argv);
|
|
257
|
+
if (tryCatch.HasCaught()) {
|
|
258
|
+
tryCatch.ReThrow();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
222
263
|
// FIXME: getting the gtype from the External is faster but doesn't
|
|
223
264
|
// work for dynamically-registered types. Check if we can find something
|
|
224
265
|
// better.
|
|
225
266
|
//gtype = (GType) External::Cast(*info.Data())->Value();
|
|
226
|
-
gtype = GET_OBJECT_GTYPE (
|
|
267
|
+
gtype = GET_OBJECT_GTYPE (proto);
|
|
227
268
|
|
|
228
269
|
gobject = CreateGObjectFromObject (gtype, info[0]);
|
|
229
270
|
|
|
@@ -330,15 +371,23 @@ static void GObjectClassDestroyed(const Nan::WeakCallbackInfo<GType> &info) {
|
|
|
330
371
|
(V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4))
|
|
331
372
|
#define PROPERTY_CALLBACK_RETURN_TYPE v8::Intercepted
|
|
332
373
|
#define PROPERTY_CALLBACK_INFO_TYPE v8::PropertyCallbackInfo<void>
|
|
374
|
+
#define PROPERTY_CALLBACK_INFO_VALUE_TYPE void
|
|
375
|
+
#define PROPERTY_CALLBACK_IS_INTERCEPTED 1
|
|
333
376
|
#else
|
|
334
377
|
#define PROPERTY_CALLBACK_RETURN_TYPE void
|
|
335
378
|
#define PROPERTY_CALLBACK_INFO_TYPE v8::PropertyCallbackInfo<Value>
|
|
379
|
+
#define PROPERTY_CALLBACK_INFO_VALUE_TYPE Value
|
|
380
|
+
#define PROPERTY_CALLBACK_IS_INTERCEPTED 0
|
|
336
381
|
#endif
|
|
337
382
|
|
|
338
383
|
static PROPERTY_CALLBACK_RETURN_TYPE
|
|
339
384
|
GObjectFallbackPropertyGetter(Local<v8::Name> property,
|
|
340
385
|
const v8::PropertyCallbackInfo<Value>& info) {
|
|
341
|
-
|
|
386
|
+
// V8 14 removed PropertyCallbackInfo::Holder(); the Nan wrapper's Holder()
|
|
387
|
+
// aliases HolderV2() on new V8 and Holder() on older V8. The handler is
|
|
388
|
+
// installed on InstanceTemplate, so the holder is the instance.
|
|
389
|
+
Nan::PropertyCallbackInfo<Value> nanInfo(info, info.Data());
|
|
390
|
+
auto self = nanInfo.Holder();
|
|
342
391
|
GObject *gobject = GObjectFromWrapper (self);
|
|
343
392
|
|
|
344
393
|
g_assert(gobject != NULL);
|
|
@@ -368,7 +417,8 @@ GObjectFallbackPropertyGetter(Local<v8::Name> property,
|
|
|
368
417
|
static PROPERTY_CALLBACK_RETURN_TYPE
|
|
369
418
|
GObjectFallbackPropertySetter(Local<v8::Name> property, Local<Value> value,
|
|
370
419
|
const PROPERTY_CALLBACK_INFO_TYPE& info) {
|
|
371
|
-
|
|
420
|
+
Nan::PropertyCallbackInfo<PROPERTY_CALLBACK_INFO_VALUE_TYPE> nanInfo(info, info.Data());
|
|
421
|
+
auto self = nanInfo.Holder();
|
|
372
422
|
GObject *gobject = GNodeJS::GObjectFromWrapper (self);
|
|
373
423
|
|
|
374
424
|
Nan::Utf8String prop_name_v (TO_STRING (property));
|
|
@@ -395,8 +445,16 @@ GObjectFallbackPropertySetter(Local<v8::Name> property, Local<Value> value,
|
|
|
395
445
|
return Nan::Intercepted::No();
|
|
396
446
|
} else {
|
|
397
447
|
// Property exists. Whether we can convert the value and set the
|
|
398
|
-
// property or not, consider the set
|
|
448
|
+
// property or not, consider the set handled.
|
|
449
|
+
#if !PROPERTY_CALLBACK_IS_INTERCEPTED
|
|
450
|
+
// Non-intercepted API (V8 <= 12.4): signal "handled" by setting the
|
|
451
|
+
// return value. Without it V8 falls through and defines a shadowing
|
|
452
|
+
// own-property on the wrapper, masking the interceptor getter (e.g. a
|
|
453
|
+
// 64-bit property would then read back as a Number, not a BigInt).
|
|
399
454
|
RETURN(value);
|
|
455
|
+
#endif
|
|
456
|
+
// Intercepted API (V8 > 12.4): the info is <void>, so signal via the
|
|
457
|
+
// Intercepted return value rather than by setting a return value.
|
|
400
458
|
g_free(prop_name);
|
|
401
459
|
return Nan::Intercepted::Yes();
|
|
402
460
|
}
|
|
@@ -458,6 +516,62 @@ static void DestroyVFuncs(GType gtype) {
|
|
|
458
516
|
g_type_set_qdata (gtype, GNodeJS::vfuncs_quark(), NULL);
|
|
459
517
|
}
|
|
460
518
|
|
|
519
|
+
/*
|
|
520
|
+
* Signal handlers are stored in a JS array held on the wrapper object itself
|
|
521
|
+
* (via a private symbol), so they are reachable only through the wrapper and
|
|
522
|
+
* the wrapper <-> handler reference loop can be garbage-collected (#375; see
|
|
523
|
+
* doc/signal-handler-gc.md). A Closure keeps only its index into that array.
|
|
524
|
+
*/
|
|
525
|
+
static Local<v8::Private> SignalHandlersKey(v8::Isolate *isolate) {
|
|
526
|
+
return v8::Private::ForApi(isolate, Nan::New("__gnodejs_signal_handlers__").ToLocalChecked());
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Append a handler to the wrapper's handler array, returning its index.
|
|
530
|
+
static guint AddSignalHandler(Local<Object> wrapper, Local<Function> handler) {
|
|
531
|
+
// Object::GetIsolate() was removed in V8 14; use the current isolate.
|
|
532
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
533
|
+
Local<v8::Context> context = isolate->GetCurrentContext();
|
|
534
|
+
Local<v8::Private> key = SignalHandlersKey(isolate);
|
|
535
|
+
|
|
536
|
+
Local<Value> existing = wrapper->GetPrivate(context, key).ToLocalChecked();
|
|
537
|
+
Local<Array> handlers;
|
|
538
|
+
if (existing->IsArray()) {
|
|
539
|
+
handlers = existing.As<Array>();
|
|
540
|
+
} else {
|
|
541
|
+
handlers = Nan::New<Array>();
|
|
542
|
+
wrapper->SetPrivate(context, key, handlers).Check();
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
guint index = handlers->Length();
|
|
546
|
+
Nan::Set(handlers, index, handler);
|
|
547
|
+
return index;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Look up a handler by the instance it is connected to and its index. Returns
|
|
551
|
+
// an empty handle if the wrapper has been collected or the slot is empty.
|
|
552
|
+
Local<Value> GetSignalHandler(GObject *gobject, guint index) {
|
|
553
|
+
void *data = g_object_get_qdata (gobject, GNodeJS::object_quark());
|
|
554
|
+
if (data == NULL)
|
|
555
|
+
return Local<Value>();
|
|
556
|
+
|
|
557
|
+
auto *wrapper = (GObjectWrapper *) data;
|
|
558
|
+
if (wrapper->collected)
|
|
559
|
+
return Local<Value>();
|
|
560
|
+
|
|
561
|
+
Local<Object> object = Nan::New(wrapper->persistent);
|
|
562
|
+
if (object.IsEmpty())
|
|
563
|
+
return Local<Value>();
|
|
564
|
+
|
|
565
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
566
|
+
Local<v8::Context> context = isolate->GetCurrentContext();
|
|
567
|
+
Local<Value> handlers =
|
|
568
|
+
object->GetPrivate(context, SignalHandlersKey(isolate)).ToLocalChecked();
|
|
569
|
+
if (!handlers->IsArray())
|
|
570
|
+
return Local<Value>();
|
|
571
|
+
|
|
572
|
+
return Nan::Get(handlers.As<Array>(), index).ToLocalChecked();
|
|
573
|
+
}
|
|
574
|
+
|
|
461
575
|
NAN_METHOD(SignalConnect) {
|
|
462
576
|
bool after = false;
|
|
463
577
|
|
|
@@ -490,9 +604,14 @@ NAN_METHOD(SignalConnect) {
|
|
|
490
604
|
guint signalId;
|
|
491
605
|
GQuark detail;
|
|
492
606
|
GClosure *gclosure;
|
|
607
|
+
guint handlerIndex;
|
|
493
608
|
gulong handler_id;
|
|
494
609
|
|
|
495
|
-
|
|
610
|
+
// Hold the Utf8String for the whole function: `*Nan::Utf8String(...)` alone
|
|
611
|
+
// dangles after the statement, and AddSignalHandler() below allocates in V8,
|
|
612
|
+
// which would clobber the freed buffer before g_signal_connect_closure.
|
|
613
|
+
Nan::Utf8String signalNameValue (TO_STRING (info[0]));
|
|
614
|
+
const char *signalName = *signalNameValue;
|
|
496
615
|
if (!g_signal_parse_name(signalName, gtype, &signalId, &detail, FALSE)) {
|
|
497
616
|
Nan::ThrowTypeError("Signal name is invalid");
|
|
498
617
|
return;
|
|
@@ -506,7 +625,8 @@ NAN_METHOD(SignalConnect) {
|
|
|
506
625
|
}
|
|
507
626
|
}
|
|
508
627
|
|
|
509
|
-
|
|
628
|
+
handlerIndex = AddSignalHandler (TO_OBJECT (info.This ()), callback);
|
|
629
|
+
gclosure = Closure::New (handlerIndex, signal_info, signalId);
|
|
510
630
|
handler_id = g_signal_connect_closure (gobject, signalName, gclosure, after);
|
|
511
631
|
|
|
512
632
|
info.GetReturnValue().Set((double)handler_id);
|
|
@@ -628,7 +748,7 @@ NAN_METHOD(GObjectToString) {
|
|
|
628
748
|
|
|
629
749
|
const char* typeName = g_type_name(type);
|
|
630
750
|
char *className = *Nan::Utf8String(self->GetConstructorName());
|
|
631
|
-
void *address = self
|
|
751
|
+
void *address = Nan::GetInternalFieldPointer(self, 0);
|
|
632
752
|
|
|
633
753
|
char *str = g_strdup_printf("[%s:%s %#zx]", typeName, className, (size_t)address);
|
|
634
754
|
|
|
@@ -691,6 +811,60 @@ static MaybeLocal<FunctionTemplate> NewClassTemplate (GType gtype) {
|
|
|
691
811
|
return MaybeLocal<FunctionTemplate> (tpl);
|
|
692
812
|
}
|
|
693
813
|
|
|
814
|
+
/*
|
|
815
|
+
* Mix the methods of a type's implemented interfaces into its class prototype.
|
|
816
|
+
*
|
|
817
|
+
* Introspectable object types get this for free: makeObject() in JS iterates
|
|
818
|
+
* their interfaces and installs the methods. Private/non-introspectable concrete
|
|
819
|
+
* types (eg GLocalFile, which implements the public GFile interface) are never
|
|
820
|
+
* seen by makeObject(), so their instances would only expose the base GObject
|
|
821
|
+
* methods. Here we enumerate the type's introspectable interfaces and hand them
|
|
822
|
+
* to the JS `interfaceMethodsApplier`, which reuses makeInterface()/define() to
|
|
823
|
+
* install the methods (and property accessors) on the class prototype.
|
|
824
|
+
*
|
|
825
|
+
* See issue #441.
|
|
826
|
+
*/
|
|
827
|
+
static void ApplyInterfaceMethods(Local<Function> constructor, GType gtype) {
|
|
828
|
+
if (interfaceMethodsApplier.IsEmpty())
|
|
829
|
+
return;
|
|
830
|
+
|
|
831
|
+
guint n_interfaces = 0;
|
|
832
|
+
GType *interfaces = g_type_interfaces(gtype, &n_interfaces);
|
|
833
|
+
|
|
834
|
+
Local<Array> refs = New<Array>();
|
|
835
|
+
uint32_t count = 0;
|
|
836
|
+
for (guint i = 0; i < n_interfaces; i++) {
|
|
837
|
+
GIBaseInfo *iface_info = g_irepository_find_by_gtype(NULL, interfaces[i]);
|
|
838
|
+
if (iface_info == NULL)
|
|
839
|
+
continue;
|
|
840
|
+
if (g_base_info_get_type(iface_info) == GI_INFO_TYPE_INTERFACE) {
|
|
841
|
+
Local<Object> ref = New<Object>();
|
|
842
|
+
Nan::Set(ref, UTF8("namespace"), UTF8(g_base_info_get_namespace(iface_info)));
|
|
843
|
+
Nan::Set(ref, UTF8("name"), UTF8(g_base_info_get_name(iface_info)));
|
|
844
|
+
Nan::Set(refs, count++, ref);
|
|
845
|
+
}
|
|
846
|
+
g_base_info_unref(iface_info);
|
|
847
|
+
}
|
|
848
|
+
g_free(interfaces);
|
|
849
|
+
|
|
850
|
+
if (count == 0)
|
|
851
|
+
return;
|
|
852
|
+
|
|
853
|
+
Local<Function> applier = New<Function>(interfaceMethodsApplier);
|
|
854
|
+
Local<Value> argv[] = { constructor, refs };
|
|
855
|
+
Nan::TryCatch tryCatch;
|
|
856
|
+
Nan::Call(applier, Nan::GetCurrentContext()->Global(), 2, argv);
|
|
857
|
+
if (tryCatch.HasCaught()) {
|
|
858
|
+
Nan::Utf8String message(tryCatch.Exception());
|
|
859
|
+
g_warning("node-gtk: could not apply interface methods for %s: %s",
|
|
860
|
+
g_type_name(gtype), *message);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
NAN_METHOD(SetInterfaceMethodsApplier) {
|
|
865
|
+
interfaceMethodsApplier.Reset(info[0].As<Function>());
|
|
866
|
+
}
|
|
867
|
+
|
|
694
868
|
static MaybeLocal<FunctionTemplate> GetClassTemplate(GType gtype) {
|
|
695
869
|
void *data = g_type_get_qdata (gtype, GNodeJS::template_quark());
|
|
696
870
|
|
|
@@ -718,6 +892,15 @@ static MaybeLocal<FunctionTemplate> GetClassTemplate(GType gtype) {
|
|
|
718
892
|
g_type_set_qdata(gtype, GNodeJS::template_quark(), persistentTpl);
|
|
719
893
|
g_type_set_qdata(gtype, GNodeJS::function_quark(), persistentFn);
|
|
720
894
|
|
|
895
|
+
// Introspectable object types have their interface methods installed by
|
|
896
|
+
// makeObject() in JS. Private concrete types are never seen there, so mix
|
|
897
|
+
// in their interface methods now (issue #441).
|
|
898
|
+
GIBaseInfo *own_info = g_irepository_find_by_gtype(NULL, gtype);
|
|
899
|
+
if (own_info == NULL)
|
|
900
|
+
ApplyInterfaceMethods(fn, gtype);
|
|
901
|
+
else
|
|
902
|
+
g_base_info_unref(own_info);
|
|
903
|
+
|
|
721
904
|
return MaybeLocal<FunctionTemplate> (tpl);
|
|
722
905
|
}
|
|
723
906
|
|
|
@@ -798,7 +981,7 @@ GObject * GObjectFromWrapper(Local<Value> value) {
|
|
|
798
981
|
|
|
799
982
|
Local<Object> object = TO_OBJECT (value);
|
|
800
983
|
|
|
801
|
-
void *ptr = object
|
|
984
|
+
void *ptr = Nan::GetInternalFieldPointer(object, 0);
|
|
802
985
|
GObject *gobject = G_OBJECT (ptr);
|
|
803
986
|
return gobject;
|
|
804
987
|
}
|
|
@@ -964,6 +1147,10 @@ out:
|
|
|
964
1147
|
}
|
|
965
1148
|
|
|
966
1149
|
|
|
1150
|
+
NAN_METHOD(SetLazyClassRegister) {
|
|
1151
|
+
lazyClassRegister.Reset(info[0].As<Function>());
|
|
1152
|
+
}
|
|
1153
|
+
|
|
967
1154
|
NAN_METHOD(RegisterClass) {
|
|
968
1155
|
auto jsKlassName = Nan::To<String>(info[0]).ToLocalChecked();
|
|
969
1156
|
auto jsKlass = info[1].As<Object>();
|
|
@@ -1034,6 +1221,78 @@ NAN_METHOD(RegisterVFunc) {
|
|
|
1034
1221
|
return;
|
|
1035
1222
|
}
|
|
1036
1223
|
|
|
1224
|
+
/*
|
|
1225
|
+
* Invoke a parent class's implementation of a vfunc — the native half of
|
|
1226
|
+
* `super.<vfunc>(...)`. JS args: (vfuncInfo, implementorGType, instance, argsArray).
|
|
1227
|
+
*
|
|
1228
|
+
* `g_vfunc_info_invoke` resolves the vfunc through `implementorGType`'s class
|
|
1229
|
+
* vtable, so passing the *parent* GType runs the parent's implementation rather
|
|
1230
|
+
* than the overriding subclass's (which is what `super` means). The instance is
|
|
1231
|
+
* passed as in-arg 0, the JS args follow.
|
|
1232
|
+
*
|
|
1233
|
+
* Scope: in-only arguments + (void or simple) return value. Out/inout arguments
|
|
1234
|
+
* are rejected rather than silently mishandled.
|
|
1235
|
+
*/
|
|
1236
|
+
NAN_METHOD(CallVFunc) {
|
|
1237
|
+
auto jsVFuncInfo = info[0].As<Object>();
|
|
1238
|
+
auto jsImplGType = info[1].As<BigInt>();
|
|
1239
|
+
auto jsInstance = info[2];
|
|
1240
|
+
auto jsArgs = info[3].As<Array>();
|
|
1241
|
+
|
|
1242
|
+
BaseInfo vfuncInfo(jsVFuncInfo);
|
|
1243
|
+
GType implementor = jsImplGType->Uint64Value();
|
|
1244
|
+
|
|
1245
|
+
int n_callable = g_callable_info_get_n_args(*vfuncInfo);
|
|
1246
|
+
|
|
1247
|
+
GObject *instance = GObjectFromWrapper(jsInstance);
|
|
1248
|
+
if (instance == NULL) {
|
|
1249
|
+
// The wrapper has no associated GObject yet — e.g. chaining up to a
|
|
1250
|
+
// construction-time vfunc (`constructed`), which fires inside g_object_new
|
|
1251
|
+
// before node-gtk associates the JS wrapper with the GObject. There is no
|
|
1252
|
+
// valid instance to invoke the parent on; fail loudly instead of crashing.
|
|
1253
|
+
Throw::Error("Cannot chain up to parent vfunc '%s': instance has no GObject yet "
|
|
1254
|
+
"(chaining up during construction is unsupported)",
|
|
1255
|
+
g_base_info_get_name(*vfuncInfo));
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
std::vector<GIArgument> in_args(n_callable + 1);
|
|
1260
|
+
in_args[0].v_pointer = instance;
|
|
1261
|
+
|
|
1262
|
+
for (int i = 0; i < n_callable; i++) {
|
|
1263
|
+
GIArgInfo arg_info;
|
|
1264
|
+
GITypeInfo arg_type;
|
|
1265
|
+
g_callable_info_load_arg(*vfuncInfo, i, &arg_info);
|
|
1266
|
+
g_arg_info_load_type(&arg_info, &arg_type);
|
|
1267
|
+
|
|
1268
|
+
if (g_arg_info_get_direction(&arg_info) != GI_DIRECTION_IN) {
|
|
1269
|
+
Throw::Error("Cannot chain up to parent vfunc '%s': out/inout argument %d is unsupported",
|
|
1270
|
+
g_base_info_get_name(*vfuncInfo), i);
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
Local<Value> value = Nan::Get(jsArgs, i).ToLocalChecked();
|
|
1275
|
+
bool may_be_null = g_arg_info_may_be_null(&arg_info);
|
|
1276
|
+
V8ToGIArgument(&arg_type, &in_args[i + 1], value, may_be_null);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
GIArgument return_value = {};
|
|
1280
|
+
GError *error = NULL;
|
|
1281
|
+
gboolean ok = g_vfunc_info_invoke(*vfuncInfo, implementor,
|
|
1282
|
+
in_args.data(), n_callable + 1, NULL, 0, &return_value, &error);
|
|
1283
|
+
|
|
1284
|
+
if (!ok) {
|
|
1285
|
+
Throw::GError("Failed to chain up to parent vfunc", error);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
GITypeInfo return_type;
|
|
1290
|
+
g_callable_info_load_return_type(*vfuncInfo, &return_type);
|
|
1291
|
+
if (g_type_info_get_tag(&return_type) != GI_TYPE_TAG_VOID) {
|
|
1292
|
+
info.GetReturnValue().Set(GIArgumentToV8(&return_type, &return_value));
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1037
1296
|
};
|
|
1038
1297
|
|
|
1039
1298
|
};
|
package/src/gobject.h
CHANGED
|
@@ -18,14 +18,19 @@ namespace GNodeJS {
|
|
|
18
18
|
MaybeLocal<Function> MakeClass (GIBaseInfo *info);
|
|
19
19
|
Local<Value> WrapperFromGObject (GObject *object);
|
|
20
20
|
GObject * GObjectFromWrapper (Local<Value> value);
|
|
21
|
+
Local<Value> GetSignalHandler (GObject *gobject, guint index);
|
|
21
22
|
Local<FunctionTemplate> GetBaseClassTemplate ();
|
|
22
23
|
MaybeLocal<Value> GetGObjectProperty (GObject * gobject, const char *prop_name);
|
|
23
24
|
MaybeLocal<v8::Boolean> SetGObjectProperty (GObject * gobject, const char *prop_name, Local<Value> value);
|
|
24
25
|
|
|
26
|
+
NAN_METHOD(SetInterfaceMethodsApplier);
|
|
27
|
+
|
|
25
28
|
namespace ObjectClass {
|
|
26
29
|
|
|
30
|
+
NAN_METHOD(SetLazyClassRegister);
|
|
27
31
|
NAN_METHOD(RegisterClass);
|
|
28
32
|
NAN_METHOD(RegisterVFunc);
|
|
33
|
+
NAN_METHOD(CallVFunc);
|
|
29
34
|
|
|
30
35
|
};
|
|
31
36
|
|