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/boxed.cc
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#include "debug.h"
|
|
7
7
|
#include "error.h"
|
|
8
8
|
#include "function.h"
|
|
9
|
+
#include "fundamental.h"
|
|
9
10
|
#include "gi.h"
|
|
10
11
|
#include "gobject.h"
|
|
11
12
|
#include "macros.h"
|
|
@@ -258,8 +259,8 @@ static void BoxedConstructor(const Nan::FunctionCallbackInfo<Value> &info) {
|
|
|
258
259
|
box->persistent = new Nan::Persistent<Object>(self);
|
|
259
260
|
box->persistent->SetWeak(box, BoxedDestroyed, Nan::WeakCallbackType::kParameter);
|
|
260
261
|
|
|
261
|
-
self
|
|
262
|
-
self
|
|
262
|
+
Nan::SetInternalFieldPointer(self, 0, boxed);
|
|
263
|
+
Nan::SetInternalFieldPointer(self, 1, box);
|
|
263
264
|
|
|
264
265
|
SET_OBJECT_GTYPE (self, gtype);
|
|
265
266
|
|
|
@@ -414,6 +415,13 @@ Local<Function> GetBoxedFunction(GIBaseInfo *info, GType gtype) {
|
|
|
414
415
|
Local<Function> MakeBoxedClass(GIBaseInfo *info) {
|
|
415
416
|
GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
|
|
416
417
|
|
|
418
|
+
// GVariant is a StructInfo but a refcounted fundamental (G_TYPE_VARIANT),
|
|
419
|
+
// not a boxed value: give it the fundamental ref/unref wrapper instead of
|
|
420
|
+
// the boxed copy/free one. JS still attaches its struct methods to this
|
|
421
|
+
// class via makeBoxed() (#465).
|
|
422
|
+
if (gtype == G_TYPE_VARIANT)
|
|
423
|
+
return MakeVariantClass (info);
|
|
424
|
+
|
|
417
425
|
if (gtype == G_TYPE_NONE) {
|
|
418
426
|
auto moduleCache = GNodeJS::GetModuleCache();
|
|
419
427
|
auto ns = UTF8 (g_base_info_get_namespace (info));
|
|
@@ -454,7 +462,7 @@ Local<Value> WrapperFromBoxed(GIBaseInfo *info, void *data, ResourceOwnership ow
|
|
|
454
462
|
void* PointerFromWrapper(Local<Value> value) {
|
|
455
463
|
Local<Object> object = TO_OBJECT (value);
|
|
456
464
|
g_assert(object->InternalFieldCount() > 0);
|
|
457
|
-
void *boxed = object
|
|
465
|
+
void *boxed = Nan::GetInternalFieldPointer(object, 0);
|
|
458
466
|
return boxed;
|
|
459
467
|
}
|
|
460
468
|
|
|
@@ -467,12 +475,12 @@ void DisownBoxed(Local<Value> value) {
|
|
|
467
475
|
if (object->InternalFieldCount() < 2)
|
|
468
476
|
return;
|
|
469
477
|
|
|
470
|
-
Boxed *box = static_cast<Boxed *>(object
|
|
478
|
+
Boxed *box = static_cast<Boxed *>(Nan::GetInternalFieldPointer(object, 1));
|
|
471
479
|
if (box != NULL) {
|
|
472
480
|
box->owns_memory = false;
|
|
473
481
|
box->data = NULL;
|
|
474
482
|
}
|
|
475
|
-
object
|
|
483
|
+
Nan::SetInternalFieldPointer(object, 0, NULL);
|
|
476
484
|
}
|
|
477
485
|
|
|
478
486
|
};
|
package/src/closure.cc
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#include "closure.h"
|
|
5
5
|
#include "error.h"
|
|
6
|
+
#include "gobject.h"
|
|
6
7
|
#include "macros.h"
|
|
7
8
|
#include "loop.h"
|
|
8
9
|
#include "type.h"
|
|
@@ -54,9 +55,9 @@ static void LoadGIArgumentFromPointer (GITypeInfo *type_info, GIArgument *arg) {
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
GClosure *Closure::New (
|
|
58
|
+
GClosure *Closure::New (guint handlerIndex, GICallableInfo* info, guint signalId) {
|
|
58
59
|
Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), GUINT_TO_POINTER(signalId));
|
|
59
|
-
closure->
|
|
60
|
+
closure->handlerIndex = handlerIndex;
|
|
60
61
|
if (info) {
|
|
61
62
|
closure->info = g_base_info_ref(info);
|
|
62
63
|
} else {
|
|
@@ -69,11 +70,18 @@ GClosure *Closure::New (Local<Function> function, GICallableInfo* info, guint si
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
void Closure::Execute(GICallableInfo *info, guint signal_id,
|
|
72
|
-
|
|
73
|
+
GObject *instance, guint handlerIndex,
|
|
73
74
|
GValue *g_return_value, guint n_param_values,
|
|
74
75
|
const GValue *param_values) {
|
|
75
76
|
Nan::HandleScope scope;
|
|
76
|
-
|
|
77
|
+
|
|
78
|
+
/* The handler lives in a JS array on the instance's wrapper (#375). If the
|
|
79
|
+
* wrapper has been collected (the object was dropped from JS) there is
|
|
80
|
+
* nothing to call. */
|
|
81
|
+
Local<Value> handlerValue = GetSignalHandler(instance, handlerIndex);
|
|
82
|
+
if (handlerValue.IsEmpty() || !handlerValue->IsFunction())
|
|
83
|
+
return;
|
|
84
|
+
auto func = handlerValue.As<Function>();
|
|
77
85
|
|
|
78
86
|
GSignalQuery signal_query = { 0, };
|
|
79
87
|
|
|
@@ -242,16 +250,21 @@ void Closure::Marshal(GClosure *base,
|
|
|
242
250
|
|
|
243
251
|
auto closure = (Closure *) base;
|
|
244
252
|
auto signal_id = GPOINTER_TO_UINT(marshal_data);
|
|
253
|
+
auto handlerIndex = closure->handlerIndex;
|
|
254
|
+
|
|
255
|
+
/* param_values[0] is always the instance the signal was emitted on, which
|
|
256
|
+
* is the object whose wrapper holds this handler (#375). */
|
|
257
|
+
GObject *instance = (GObject *) g_value_get_object(¶m_values[0]);
|
|
245
258
|
|
|
246
259
|
AsyncCallEnvironment* env = reinterpret_cast<AsyncCallEnvironment *>(AsyncCallEnvironment::asyncHandle.data);
|
|
247
260
|
|
|
248
261
|
if (env->IsSameThread()) {
|
|
249
262
|
/* Case 1: same thread */
|
|
250
|
-
Closure::Execute(closure->info, signal_id,
|
|
263
|
+
Closure::Execute(closure->info, signal_id, instance, handlerIndex, g_return_value, n_param_values, param_values);
|
|
251
264
|
} else {
|
|
252
265
|
/* Case 2: different thread */
|
|
253
266
|
env->Call([&]() {
|
|
254
|
-
Closure::Execute(closure->info, signal_id,
|
|
267
|
+
Closure::Execute(closure->info, signal_id, instance, handlerIndex, g_return_value, n_param_values, param_values);
|
|
255
268
|
});
|
|
256
269
|
}
|
|
257
270
|
}
|
package/src/closure.h
CHANGED
|
@@ -16,20 +16,24 @@ namespace GNodeJS {
|
|
|
16
16
|
|
|
17
17
|
struct Closure {
|
|
18
18
|
GClosure base;
|
|
19
|
-
|
|
19
|
+
/* The handler function is NOT held here. It lives in a JS array on the
|
|
20
|
+
* wrapper object (reachable only through the wrapper), and we keep just its
|
|
21
|
+
* index. This breaks the wrapper <-> handler reference loop that a strong
|
|
22
|
+
* Nan::Persistent used to create and leak (#375); see
|
|
23
|
+
* doc/signal-handler-gc.md. */
|
|
24
|
+
guint handlerIndex;
|
|
20
25
|
GICallableInfo* info;
|
|
21
26
|
|
|
22
27
|
~Closure() {
|
|
23
|
-
persistent.Reset();
|
|
24
28
|
if (info) g_base_info_unref (info);
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
static GClosure *New(
|
|
31
|
+
static GClosure *New(guint handlerIndex,
|
|
28
32
|
GICallableInfo* info,
|
|
29
33
|
guint signalId);
|
|
30
34
|
|
|
31
35
|
static void Execute(GICallableInfo *info, guint signal_id,
|
|
32
|
-
|
|
36
|
+
GObject *instance, guint handlerIndex,
|
|
33
37
|
GValue *g_return_value, guint n_param_values,
|
|
34
38
|
const GValue *param_values);
|
|
35
39
|
|
package/src/function.cc
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include "callback.h"
|
|
6
6
|
#include "debug.h"
|
|
7
7
|
#include "error.h"
|
|
8
|
+
#include "fundamental.h"
|
|
8
9
|
#include "function.h"
|
|
9
10
|
#include "gobject.h"
|
|
10
11
|
#include "macros.h"
|
|
@@ -134,6 +135,43 @@ bool IsDestroyNotify (GIBaseInfo *info) {
|
|
|
134
135
|
&& strcmp(g_base_info_get_namespace(info), "GLib") == 0;
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
/*
|
|
139
|
+
* A transfer-full GObject return value hands node-gtk an *owning* reference. The
|
|
140
|
+
* JS wrapper only needs node-gtk's toggle reference, so that extra reference has
|
|
141
|
+
* to be released — otherwise the refcount never falls back to 1, ToggleNotify
|
|
142
|
+
* never flips the V8 handle to weak, and the GObject (plus its wrapper) leaks for
|
|
143
|
+
* the lifetime of the process. This is the leak reported in #446: objects from
|
|
144
|
+
* GI function returns (`Type.new()`, transfer-full getters, …) were never GC'd,
|
|
145
|
+
* while `new Type()` — which drops its construction ref in GObjectConstructor —
|
|
146
|
+
* was. It is the return-value counterpart of OUT GObject args, which
|
|
147
|
+
* FreeGIArgument already balances; the return value is otherwise never freed on
|
|
148
|
+
* the success path. (The IN counterpart is RefObjectForTransferFullIn, #439.)
|
|
149
|
+
*
|
|
150
|
+
* Must be sampled *before* the value is wrapped: associating the wrapper sinks a
|
|
151
|
+
* floating reference (consuming it), after which a floating incoming ref (nothing
|
|
152
|
+
* extra to drop) is indistinguishable from a real owned one. G_IS_OBJECT excludes
|
|
153
|
+
* GParamSpec (wrapped via ParamSpec::FromGParamSpec) and boxed/fundamental
|
|
154
|
+
* interface types.
|
|
155
|
+
*/
|
|
156
|
+
static bool OwnsExtraGObjectReturnRef(GITypeInfo *return_type, GITransfer transfer, gpointer ptr) {
|
|
157
|
+
if (transfer != GI_TRANSFER_EVERYTHING || ptr == NULL)
|
|
158
|
+
return false;
|
|
159
|
+
|
|
160
|
+
if (g_type_info_get_tag(return_type) != GI_TYPE_TAG_INTERFACE)
|
|
161
|
+
return false;
|
|
162
|
+
|
|
163
|
+
GIBaseInfo *iface = g_type_info_get_interface(return_type);
|
|
164
|
+
GIInfoType itype = g_base_info_get_type(iface);
|
|
165
|
+
|
|
166
|
+
bool result =
|
|
167
|
+
(itype == GI_INFO_TYPE_OBJECT || itype == GI_INFO_TYPE_INTERFACE)
|
|
168
|
+
&& G_IS_OBJECT(ptr)
|
|
169
|
+
&& !g_object_is_floating(ptr);
|
|
170
|
+
|
|
171
|
+
g_base_info_unref(iface);
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
137
175
|
|
|
138
176
|
/**
|
|
139
177
|
* The constructor just stores the GIBaseInfo ref. The rest of the
|
|
@@ -485,11 +523,14 @@ Local<Value> FunctionCall (
|
|
|
485
523
|
// Boxed: hand it a copy so the JS wrapper's own memory isn't
|
|
486
524
|
// double-freed when finalized (#409). GObject: add the reference
|
|
487
525
|
// the callee will own, so it isn't finalized out from under the
|
|
488
|
-
// callee once the wrapper is GC'd (#439).
|
|
526
|
+
// callee once the wrapper is GC'd (#439). Fundamental (e.g.
|
|
527
|
+
// GskRenderNode): add the reference the callee will own (#468).
|
|
489
528
|
else if (direction == GI_DIRECTION_IN
|
|
490
529
|
&& g_arg_info_get_ownership_transfer(&arg_info) == GI_TRANSFER_EVERYTHING) {
|
|
491
530
|
CopyBoxedForTransferFullIn(&type_info, &callable_arg_values[i], param.length);
|
|
492
531
|
RefObjectForTransferFullIn(&type_info, &callable_arg_values[i]);
|
|
532
|
+
RefFundamentalForTransferFullIn(&type_info, &callable_arg_values[i]);
|
|
533
|
+
RefVariantForTransferFullIn(&type_info, &callable_arg_values[i]);
|
|
493
534
|
}
|
|
494
535
|
}
|
|
495
536
|
|
|
@@ -549,6 +590,13 @@ Local<Value> FunctionCall (
|
|
|
549
590
|
|
|
550
591
|
} else if (!use_return_value) {
|
|
551
592
|
|
|
593
|
+
// A transfer-full GObject return hands us an extra owning reference on
|
|
594
|
+
// top of the wrapper's toggle ref; drop it once wrapped so the object
|
|
595
|
+
// isn't pinned alive forever (#446). Sampled now, before wrapping sinks
|
|
596
|
+
// any floating reference.
|
|
597
|
+
bool release_return_ref =
|
|
598
|
+
OwnsExtraGObjectReturnRef(&return_type, return_transfer, return_value_stack.v_pointer);
|
|
599
|
+
|
|
552
600
|
// Value transferred to jsReturnValue
|
|
553
601
|
jsReturnValue = func->JsReturnValue (
|
|
554
602
|
info.This(),
|
|
@@ -556,6 +604,9 @@ Local<Value> FunctionCall (
|
|
|
556
604
|
&return_value_stack,
|
|
557
605
|
callable_arg_values,
|
|
558
606
|
return_transfer);
|
|
607
|
+
|
|
608
|
+
if (release_return_ref)
|
|
609
|
+
g_object_unref (return_value_stack.v_pointer);
|
|
559
610
|
} else {
|
|
560
611
|
|
|
561
612
|
// Value returned in return_value
|
|
@@ -661,7 +712,8 @@ Local<Value> FunctionInfo::JsReturnValue (
|
|
|
661
712
|
ADD_RETURN (isReturningSelf ? self :
|
|
662
713
|
GIArgumentToV8 (
|
|
663
714
|
return_type, return_value, length,
|
|
664
|
-
return_transfer == GI_TRANSFER_EVERYTHING ? kTransfer : kNone
|
|
715
|
+
return_transfer == GI_TRANSFER_EVERYTHING ? kTransfer : kNone,
|
|
716
|
+
g_callable_info_may_return_null (info)))
|
|
665
717
|
}
|
|
666
718
|
|
|
667
719
|
for (int i = 0; i < n_callable_args; i++) {
|
|
@@ -695,20 +747,22 @@ Local<Value> FunctionInfo::JsReturnValue (
|
|
|
695
747
|
&callable_arg_values[length_i],
|
|
696
748
|
IsDirectionOut(length_direction));
|
|
697
749
|
|
|
698
|
-
|
|
750
|
+
bool may_be_null = g_arg_info_may_be_null(&arg_info);
|
|
751
|
+
Local<Value> result = ArrayToV8(&arg_type, *(void**)arg_value.v_pointer, param.length, may_be_null);
|
|
699
752
|
|
|
700
753
|
ADD_RETURN (result)
|
|
701
754
|
|
|
702
755
|
} else if (param.type == ParameterType::kNORMAL) {
|
|
703
756
|
GITransfer transfer = g_arg_info_get_ownership_transfer(&arg_info);
|
|
704
757
|
ResourceOwnership ownership = transfer == GI_TRANSFER_EVERYTHING ? kTransfer : kNone;
|
|
758
|
+
bool may_be_null = g_arg_info_may_be_null(&arg_info);
|
|
705
759
|
|
|
706
760
|
if (IsPointerType(&arg_type) && g_arg_info_is_caller_allocates(&arg_info)) {
|
|
707
761
|
void *pointer = &arg_value.v_pointer;
|
|
708
|
-
ADD_RETURN (GIArgumentToV8(&arg_type, (GIArgument*) pointer, -1, ownership))
|
|
762
|
+
ADD_RETURN (GIArgumentToV8(&arg_type, (GIArgument*) pointer, -1, ownership, may_be_null))
|
|
709
763
|
}
|
|
710
764
|
else {
|
|
711
|
-
ADD_RETURN (GIArgumentToV8(&arg_type, (GIArgument*) arg_value.v_pointer, -1, ownership))
|
|
765
|
+
ADD_RETURN (GIArgumentToV8(&arg_type, (GIArgument*) arg_value.v_pointer, -1, ownership, may_be_null))
|
|
712
766
|
}
|
|
713
767
|
}
|
|
714
768
|
}
|