node-gtk 3.0.0 → 4.0.1
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 +1 -1
- package/binding.gyp +21 -0
- package/lib/bootstrap.js +43 -11
- package/lib/loop.js +13 -1
- package/lib/overrides/Gtk-4.0.js +6 -27
- package/package.json +1 -2
- package/src/boxed.cc +13 -5
- package/src/function.cc +12 -5
- package/src/fundamental.cc +451 -0
- package/src/fundamental.h +71 -0
- package/src/gi.cc +11 -1
- package/src/gobject.cc +100 -8
- package/src/gobject.h +2 -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/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
`node-gtk` lets you build native GTK apps on **linux**, **macOS** and **windows**
|
|
24
24
|
with full **ESM**, **TypeScript** and **CSS hot-reload** support. Prebuilt binaries
|
|
25
|
-
are available for Node.js versions **
|
|
25
|
+
are available for Node.js versions **22**, **24** and **26**.
|
|
26
26
|
|
|
27
27
|
<p align="center">
|
|
28
28
|
<img src="./img/browser.png" style="max-width: 500px; height: auto;" alt="A web browser build with node-gtk" />
|
package/binding.gyp
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
+
# Node 26's official Windows binary is built with ClangCL + ThinLTO, so its
|
|
3
|
+
# common.gypi injects `-flto=thin` and `/opt:lldltojobs=N` into the MSVC
|
|
4
|
+
# AdditionalOptions of every target. MSVC's link.exe rejects those
|
|
5
|
+
# Clang/lld-only options (LNK1117), which breaks the build on Windows +
|
|
6
|
+
# Node 26. Strip them with gyp's list-exclusion filter. This lives under
|
|
7
|
+
# msvs_settings, so it is inert on the make/xcode generators (Linux/macOS).
|
|
8
|
+
"target_defaults": {
|
|
9
|
+
"configurations": {
|
|
10
|
+
"Release": {
|
|
11
|
+
"msvs_settings": {
|
|
12
|
+
"VCCLCompilerTool": {
|
|
13
|
+
"AdditionalOptions/": [ ["exclude", "flto"] ]
|
|
14
|
+
},
|
|
15
|
+
"VCLinkerTool": {
|
|
16
|
+
"AdditionalOptions/": [ ["exclude", "flto"], ["exclude", "lldltojobs"] ]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
2
22
|
"targets": [
|
|
3
23
|
{
|
|
4
24
|
"target_name": "node_gtk",
|
|
@@ -11,6 +31,7 @@
|
|
|
11
31
|
"src/debug.cc",
|
|
12
32
|
"src/error.cc",
|
|
13
33
|
"src/function.cc",
|
|
34
|
+
"src/fundamental.cc",
|
|
14
35
|
"src/gi.cc",
|
|
15
36
|
"src/gobject.cc",
|
|
16
37
|
"src/loop.cc",
|
package/lib/bootstrap.js
CHANGED
|
@@ -292,23 +292,55 @@ function makeObject(info) {
|
|
|
292
292
|
*/
|
|
293
293
|
|
|
294
294
|
forLoopFn(info, GI.object_info_get_n_interfaces, GI.object_info_get_interface, (interfaceInfo) => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
interface_._properties.forEach(description => {
|
|
298
|
-
define(constructor, description)
|
|
299
|
-
})
|
|
300
|
-
interface_._methods.forEach(description => {
|
|
301
|
-
define(constructor, description)
|
|
302
|
-
})
|
|
303
|
-
interface_._constants.forEach(description => {
|
|
304
|
-
define(constructor, description)
|
|
305
|
-
})
|
|
295
|
+
applyInterface(constructor, getInterface(interfaceInfo))
|
|
306
296
|
})
|
|
307
297
|
|
|
308
298
|
|
|
309
299
|
return constructor;
|
|
310
300
|
}
|
|
311
301
|
|
|
302
|
+
/*
|
|
303
|
+
* Mix an interface's properties/methods/constants (as prepared by
|
|
304
|
+
* makeInterface) into a class constructor. Shared by makeObject() and the
|
|
305
|
+
* `applyInterfaceMethods` callback below.
|
|
306
|
+
*/
|
|
307
|
+
function applyInterface(constructor, interface_) {
|
|
308
|
+
interface_._properties.forEach(description => define(constructor, description))
|
|
309
|
+
interface_._methods.forEach(description => define(constructor, description))
|
|
310
|
+
interface_._constants.forEach(description => define(constructor, description))
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*
|
|
314
|
+
* Called from C++ (GetClassTemplate) the first time a private/non-introspectable
|
|
315
|
+
* concrete type is wrapped, to install the methods of the interfaces it
|
|
316
|
+
* implements onto its prototype. makeObject() never runs for such types, so
|
|
317
|
+
* without this their instances would only expose the base GObject methods
|
|
318
|
+
* (issue #441). `interfaceRefs` is an array of { namespace, name }.
|
|
319
|
+
*/
|
|
320
|
+
function applyInterfaceMethods(constructor, interfaceRefs) {
|
|
321
|
+
const repo = GI.Repository_get_default()
|
|
322
|
+
|
|
323
|
+
interfaceRefs.forEach(({ namespace, name }) => {
|
|
324
|
+
const cache = moduleCache[namespace]
|
|
325
|
+
// The interface's module must be loaded for its constructor to exist; if it
|
|
326
|
+
// isn't, there is nothing meaningful to install.
|
|
327
|
+
if (!cache)
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
let interface_ = cache[name]
|
|
331
|
+
if (!interface_) {
|
|
332
|
+
const info = GI.Repository_find_by_name.call(repo, namespace, name)
|
|
333
|
+
if (!info)
|
|
334
|
+
return
|
|
335
|
+
interface_ = getInterface(info)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
applyInterface(constructor, interface_)
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
internal.SetInterfaceMethodsApplier(applyInterfaceMethods)
|
|
343
|
+
|
|
312
344
|
function makeBoxed(info) {
|
|
313
345
|
if (getType(info) == GI.InfoType.UNION) {
|
|
314
346
|
return makeUnion(info)
|
package/lib/loop.js
CHANGED
|
@@ -45,10 +45,22 @@ function start() {
|
|
|
45
45
|
* macrotask lets the module's top-level microtask return first, so the queue
|
|
46
46
|
* drains and the loop integration takes over from a clean (non-nested) state.
|
|
47
47
|
*
|
|
48
|
+
* We defer with setTimeout, NOT setImmediate. A setImmediate callback runs
|
|
49
|
+
* *inside* Node's immediate-processing machinery (native CheckImmediate ->
|
|
50
|
+
* processImmediate). Because `run` never returns (it blocks in the GLib main
|
|
51
|
+
* loop until the app quits), CheckImmediate never reaches the code that stops
|
|
52
|
+
* Node's private immediate uv_idle handle, so that handle stays active forever.
|
|
53
|
+
* An active idle handle pins uv_backend_timeout() at 0, which makes the nested
|
|
54
|
+
* uv-in-GLib loop busy-spin at 100% CPU (worse on Node 26 / libuv 1.52, where
|
|
55
|
+
* the immediate's wakeup eventfd also stays signalled). A one-shot timer is
|
|
56
|
+
* removed from libuv's timer heap before its callback runs, so blocking inside
|
|
57
|
+
* it leaves no libuv state active and the loop can sleep normally. See #477.
|
|
58
|
+
*
|
|
48
59
|
* Under CommonJS (and inside signal callbacks) we are not in a microtask, so we
|
|
49
60
|
* run synchronously and preserve the original blocking semantics exactly.
|
|
50
61
|
*
|
|
51
62
|
* https://github.com/romgrk/node-gtk/issues/442
|
|
63
|
+
* https://github.com/romgrk/node-gtk/issues/477
|
|
52
64
|
*
|
|
53
65
|
* Returns the native call's result when run synchronously (so e.g.
|
|
54
66
|
* `const status = app.run()` keeps working under CommonJS); returns undefined
|
|
@@ -64,7 +76,7 @@ function runLoopEntry(run) {
|
|
|
64
76
|
start()
|
|
65
77
|
|
|
66
78
|
if (internal.IsRunningMicrotasks()) {
|
|
67
|
-
|
|
79
|
+
setTimeout(run, 0)
|
|
68
80
|
return undefined
|
|
69
81
|
}
|
|
70
82
|
return run()
|
package/lib/overrides/Gtk-4.0.js
CHANGED
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
* Gtk-4.0.js
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const internal = require('../native.js')
|
|
6
|
-
const Module = require('../module')
|
|
7
|
-
const Gio = Module.require('Gio')
|
|
8
|
-
|
|
9
5
|
exports.apply = (Gtk) => {
|
|
10
6
|
|
|
11
7
|
Gtk.EVENT_CONTINUE = false
|
|
@@ -104,29 +100,12 @@ exports.apply = (Gtk) => {
|
|
|
104
100
|
return tickId
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*/
|
|
113
|
-
Gtk.FileChooserDialog.prototype.getFile = function getFile() {
|
|
114
|
-
const file = originalGetFile.call(this)
|
|
115
|
-
if (file)
|
|
116
|
-
file.__proto__= Gio.File.prototype
|
|
117
|
-
return file
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Gtk.FileChooserWidget.prototype.getFile
|
|
122
|
-
* @returns {GFile} - The file
|
|
123
|
-
*/
|
|
124
|
-
Gtk.FileChooserWidget.prototype.getFile = function getFile() {
|
|
125
|
-
const file = originalGetFile.call(this)
|
|
126
|
-
if (file)
|
|
127
|
-
file.__proto__= Gio.File.prototype
|
|
128
|
-
return file
|
|
129
|
-
}
|
|
103
|
+
/* getFile() used to need a manual `file.__proto__ = Gio.File.prototype` fixup
|
|
104
|
+
* because the returned GLocalFile is a private type whose GFile interface
|
|
105
|
+
* methods weren't mixed into its prototype. That is now handled generically
|
|
106
|
+
* for every private type at wrap time (see issue #441), so the override is no
|
|
107
|
+
* longer necessary — the introspected getFile() returns a fully-usable file
|
|
108
|
+
* (or null when nothing is selected). */
|
|
130
109
|
}
|
|
131
110
|
|
|
132
111
|
function easeOutCubic(t) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-gtk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "GNOME Gtk+ bindings for NodeJS",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"assert": "^1.5.0",
|
|
65
65
|
"aws-sdk": "^2.452.0",
|
|
66
66
|
"chalk": "^2.4.2",
|
|
67
|
-
"deasync": "^0.1.30",
|
|
68
67
|
"mocha": "^7.1.0",
|
|
69
68
|
"nid-parser": "0.0.5",
|
|
70
69
|
"node-pre-gyp-github": "^1.4.5"
|
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/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"
|
|
@@ -522,11 +523,14 @@ Local<Value> FunctionCall (
|
|
|
522
523
|
// Boxed: hand it a copy so the JS wrapper's own memory isn't
|
|
523
524
|
// double-freed when finalized (#409). GObject: add the reference
|
|
524
525
|
// the callee will own, so it isn't finalized out from under the
|
|
525
|
-
// 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).
|
|
526
528
|
else if (direction == GI_DIRECTION_IN
|
|
527
529
|
&& g_arg_info_get_ownership_transfer(&arg_info) == GI_TRANSFER_EVERYTHING) {
|
|
528
530
|
CopyBoxedForTransferFullIn(&type_info, &callable_arg_values[i], param.length);
|
|
529
531
|
RefObjectForTransferFullIn(&type_info, &callable_arg_values[i]);
|
|
532
|
+
RefFundamentalForTransferFullIn(&type_info, &callable_arg_values[i]);
|
|
533
|
+
RefVariantForTransferFullIn(&type_info, &callable_arg_values[i]);
|
|
530
534
|
}
|
|
531
535
|
}
|
|
532
536
|
|
|
@@ -708,7 +712,8 @@ Local<Value> FunctionInfo::JsReturnValue (
|
|
|
708
712
|
ADD_RETURN (isReturningSelf ? self :
|
|
709
713
|
GIArgumentToV8 (
|
|
710
714
|
return_type, return_value, length,
|
|
711
|
-
return_transfer == GI_TRANSFER_EVERYTHING ? kTransfer : kNone
|
|
715
|
+
return_transfer == GI_TRANSFER_EVERYTHING ? kTransfer : kNone,
|
|
716
|
+
g_callable_info_may_return_null (info)))
|
|
712
717
|
}
|
|
713
718
|
|
|
714
719
|
for (int i = 0; i < n_callable_args; i++) {
|
|
@@ -742,20 +747,22 @@ Local<Value> FunctionInfo::JsReturnValue (
|
|
|
742
747
|
&callable_arg_values[length_i],
|
|
743
748
|
IsDirectionOut(length_direction));
|
|
744
749
|
|
|
745
|
-
|
|
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);
|
|
746
752
|
|
|
747
753
|
ADD_RETURN (result)
|
|
748
754
|
|
|
749
755
|
} else if (param.type == ParameterType::kNORMAL) {
|
|
750
756
|
GITransfer transfer = g_arg_info_get_ownership_transfer(&arg_info);
|
|
751
757
|
ResourceOwnership ownership = transfer == GI_TRANSFER_EVERYTHING ? kTransfer : kNone;
|
|
758
|
+
bool may_be_null = g_arg_info_may_be_null(&arg_info);
|
|
752
759
|
|
|
753
760
|
if (IsPointerType(&arg_type) && g_arg_info_is_caller_allocates(&arg_info)) {
|
|
754
761
|
void *pointer = &arg_value.v_pointer;
|
|
755
|
-
ADD_RETURN (GIArgumentToV8(&arg_type, (GIArgument*) pointer, -1, ownership))
|
|
762
|
+
ADD_RETURN (GIArgumentToV8(&arg_type, (GIArgument*) pointer, -1, ownership, may_be_null))
|
|
756
763
|
}
|
|
757
764
|
else {
|
|
758
|
-
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))
|
|
759
766
|
}
|
|
760
767
|
}
|
|
761
768
|
}
|