node-gtk 3.0.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/src/gobject.cc CHANGED
@@ -40,6 +40,11 @@ static Nan::Persistent<FunctionTemplate> baseTemplate;
40
40
  // this makes registerClass() optional. Empty until JS installs it.
41
41
  static Nan::Persistent<Function> lazyClassRegister;
42
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
+
43
48
 
44
49
  static MaybeLocal<FunctionTemplate> GetClassTemplate(GType gtype);
45
50
  static MaybeLocal<Function> GetClass(GType gtype);
@@ -170,7 +175,7 @@ static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_d
170
175
  }
171
176
 
172
177
  static void AssociateGObject(Local<Object> object, GObject *gobject, GType gtype) {
173
- object->SetAlignedPointerInInternalField (0, gobject);
178
+ Nan::SetInternalFieldPointer(object, 0, gobject);
174
179
 
175
180
  SET_OBJECT_GTYPE(object, gtype);
176
181
 
@@ -226,7 +231,13 @@ static void GObjectConstructor(const FunctionCallbackInfo<Value> &info) {
226
231
 
227
232
  /* User code calling `new Gtk.Widget({ ... })` */
228
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
229
239
  Local<Object> proto = Nan::To<Object>(self->GetPrototype()).ToLocalChecked();
240
+ #endif
230
241
 
231
242
  /* A JS subclass (`class Foo extends Gtk.Widget {}`) that was never passed to
232
243
  * registerClass() owns no GType: `__gtype__` is only *inherited* from its
@@ -360,15 +371,23 @@ static void GObjectClassDestroyed(const Nan::WeakCallbackInfo<GType> &info) {
360
371
  (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4))
361
372
  #define PROPERTY_CALLBACK_RETURN_TYPE v8::Intercepted
362
373
  #define PROPERTY_CALLBACK_INFO_TYPE v8::PropertyCallbackInfo<void>
374
+ #define PROPERTY_CALLBACK_INFO_VALUE_TYPE void
375
+ #define PROPERTY_CALLBACK_IS_INTERCEPTED 1
363
376
  #else
364
377
  #define PROPERTY_CALLBACK_RETURN_TYPE void
365
378
  #define PROPERTY_CALLBACK_INFO_TYPE v8::PropertyCallbackInfo<Value>
379
+ #define PROPERTY_CALLBACK_INFO_VALUE_TYPE Value
380
+ #define PROPERTY_CALLBACK_IS_INTERCEPTED 0
366
381
  #endif
367
382
 
368
383
  static PROPERTY_CALLBACK_RETURN_TYPE
369
384
  GObjectFallbackPropertyGetter(Local<v8::Name> property,
370
385
  const v8::PropertyCallbackInfo<Value>& info) {
371
- auto self = info.Holder();
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();
372
391
  GObject *gobject = GObjectFromWrapper (self);
373
392
 
374
393
  g_assert(gobject != NULL);
@@ -398,7 +417,8 @@ GObjectFallbackPropertyGetter(Local<v8::Name> property,
398
417
  static PROPERTY_CALLBACK_RETURN_TYPE
399
418
  GObjectFallbackPropertySetter(Local<v8::Name> property, Local<Value> value,
400
419
  const PROPERTY_CALLBACK_INFO_TYPE& info) {
401
- auto self = info.Holder();
420
+ Nan::PropertyCallbackInfo<PROPERTY_CALLBACK_INFO_VALUE_TYPE> nanInfo(info, info.Data());
421
+ auto self = nanInfo.Holder();
402
422
  GObject *gobject = GNodeJS::GObjectFromWrapper (self);
403
423
 
404
424
  Nan::Utf8String prop_name_v (TO_STRING (property));
@@ -425,8 +445,16 @@ GObjectFallbackPropertySetter(Local<v8::Name> property, Local<Value> value,
425
445
  return Nan::Intercepted::No();
426
446
  } else {
427
447
  // Property exists. Whether we can convert the value and set the
428
- // property or not, consider the set intercepted.
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).
429
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.
430
458
  g_free(prop_name);
431
459
  return Nan::Intercepted::Yes();
432
460
  }
@@ -500,7 +528,8 @@ static Local<v8::Private> SignalHandlersKey(v8::Isolate *isolate) {
500
528
 
501
529
  // Append a handler to the wrapper's handler array, returning its index.
502
530
  static guint AddSignalHandler(Local<Object> wrapper, Local<Function> handler) {
503
- v8::Isolate *isolate = wrapper->GetIsolate();
531
+ // Object::GetIsolate() was removed in V8 14; use the current isolate.
532
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
504
533
  Local<v8::Context> context = isolate->GetCurrentContext();
505
534
  Local<v8::Private> key = SignalHandlersKey(isolate);
506
535
 
@@ -533,7 +562,7 @@ Local<Value> GetSignalHandler(GObject *gobject, guint index) {
533
562
  if (object.IsEmpty())
534
563
  return Local<Value>();
535
564
 
536
- v8::Isolate *isolate = object->GetIsolate();
565
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
537
566
  Local<v8::Context> context = isolate->GetCurrentContext();
538
567
  Local<Value> handlers =
539
568
  object->GetPrivate(context, SignalHandlersKey(isolate)).ToLocalChecked();
@@ -719,7 +748,7 @@ NAN_METHOD(GObjectToString) {
719
748
 
720
749
  const char* typeName = g_type_name(type);
721
750
  char *className = *Nan::Utf8String(self->GetConstructorName());
722
- void *address = self->GetAlignedPointerFromInternalField(0);
751
+ void *address = Nan::GetInternalFieldPointer(self, 0);
723
752
 
724
753
  char *str = g_strdup_printf("[%s:%s %#zx]", typeName, className, (size_t)address);
725
754
 
@@ -782,6 +811,60 @@ static MaybeLocal<FunctionTemplate> NewClassTemplate (GType gtype) {
782
811
  return MaybeLocal<FunctionTemplate> (tpl);
783
812
  }
784
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
+
785
868
  static MaybeLocal<FunctionTemplate> GetClassTemplate(GType gtype) {
786
869
  void *data = g_type_get_qdata (gtype, GNodeJS::template_quark());
787
870
 
@@ -809,6 +892,15 @@ static MaybeLocal<FunctionTemplate> GetClassTemplate(GType gtype) {
809
892
  g_type_set_qdata(gtype, GNodeJS::template_quark(), persistentTpl);
810
893
  g_type_set_qdata(gtype, GNodeJS::function_quark(), persistentFn);
811
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
+
812
904
  return MaybeLocal<FunctionTemplate> (tpl);
813
905
  }
814
906
 
@@ -889,7 +981,7 @@ GObject * GObjectFromWrapper(Local<Value> value) {
889
981
 
890
982
  Local<Object> object = TO_OBJECT (value);
891
983
 
892
- void *ptr = object->GetAlignedPointerFromInternalField (0);
984
+ void *ptr = Nan::GetInternalFieldPointer(object, 0);
893
985
  GObject *gobject = G_OBJECT (ptr);
894
986
  return gobject;
895
987
  }
package/src/gobject.h CHANGED
@@ -23,6 +23,8 @@ Local<FunctionTemplate> GetBaseClassTemplate ();
23
23
  MaybeLocal<Value> GetGObjectProperty (GObject * gobject, const char *prop_name);
24
24
  MaybeLocal<v8::Boolean> SetGObjectProperty (GObject * gobject, const char *prop_name, Local<Value> value);
25
25
 
26
+ NAN_METHOD(SetInterfaceMethodsApplier);
27
+
26
28
  namespace ObjectClass {
27
29
 
28
30
  NAN_METHOD(SetLazyClassRegister);