@gjsify/node-gi 0.32.0 → 0.34.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/gtk-runtime.js +29 -0
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node_gi.node +0 -0
- package/prebuilds/darwin-x64/node_gi.node +0 -0
- package/prebuilds/linux-arm64/node_gi.node +0 -0
- package/prebuilds/linux-x64/node_gi.node +0 -0
- package/prebuilds/win32-x64/node_gi.node +0 -0
- package/src/template.cc +74 -39
package/gtk-runtime.js
CHANGED
|
@@ -426,6 +426,35 @@ export function maybeWireGtkWindowingEnv() {
|
|
|
426
426
|
setIfUnset('FONTCONFIG_PATH', join(bundle.dir, 'etc', 'fonts'));
|
|
427
427
|
setIfUnset('FONTCONFIG_FILE', fontsConf);
|
|
428
428
|
}
|
|
429
|
+
|
|
430
|
+
// GStreamer, which finds its plugins the way GTK finds its schemas: by env,
|
|
431
|
+
// read at init. Without this the bundle can ship every Gst typelib and still
|
|
432
|
+
// play nothing — `Gst.init()` succeeds against an EMPTY registry, so the
|
|
433
|
+
// failure surfaces far away as "no element decodebin" rather than as a missing
|
|
434
|
+
// library. That is the same shape as the 0.27.1 bundles, which carried
|
|
435
|
+
// `Adw-1.typelib` with no libadwaita behind it.
|
|
436
|
+
//
|
|
437
|
+
// SYSTEM_PATH, not GST_PLUGIN_PATH: the latter is the USER's additive override
|
|
438
|
+
// and the bundle has no business consuming it. SYSTEM_PATH also suppresses the
|
|
439
|
+
// compiled-in default, which is what we want — that default is the build
|
|
440
|
+
// machine's prefix, and on a user's box it is either absent or, worse, a
|
|
441
|
+
// foreign GStreamer whose plugins would be mixed with the bundle's.
|
|
442
|
+
const gstPlugins = join(bundle.dir, 'lib', 'gstreamer-1.0');
|
|
443
|
+
if (existsSync(gstPlugins)) {
|
|
444
|
+
setIfUnset('GST_PLUGIN_SYSTEM_PATH', gstPlugins);
|
|
445
|
+
// The scanner is a separate EXECUTABLE that GStreamer forks to inspect each
|
|
446
|
+
// plugin out-of-process, so a plugin that crashes on load cannot take the
|
|
447
|
+
// app with it. Its compiled-in path is the build machine's too, so without
|
|
448
|
+
// this GStreamer silently degrades to in-process scanning — which works,
|
|
449
|
+
// until the first bad plugin takes the process down instead of itself.
|
|
450
|
+
const scanner = join(bundle.dir, 'libexec', 'gstreamer-1.0', gstScannerLeaf());
|
|
451
|
+
if (existsSync(scanner)) setIfUnset('GST_PLUGIN_SCANNER', scanner);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** The plugin scanner's leaf name — the bundles ship the same tree on both OSes. */
|
|
456
|
+
function gstScannerLeaf() {
|
|
457
|
+
return process.platform === 'win32' ? 'gst-plugin-scanner.exe' : 'gst-plugin-scanner';
|
|
429
458
|
}
|
|
430
459
|
|
|
431
460
|
let activated = null; // memoize: the activation result (idempotent)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/node-gi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "GObject-Introspection runtime for Node.js — load gi:// namespaces (GLib/GObject/Gio/…) with GJS-compatible semantics. Vendored + rewritten from node-gtk under MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/template.cc
CHANGED
|
@@ -5,67 +5,102 @@
|
|
|
5
5
|
|
|
6
6
|
namespace nodegi {
|
|
7
7
|
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
// The GTK 4 shared library, opened by leaf name. THREE things vary per OS and
|
|
11
|
+
// nothing else does, so only those three are spelled per-OS — the symbol table in
|
|
12
|
+
// the function below is written once and both sides run it.
|
|
13
|
+
//
|
|
14
|
+
// The LEAF NAME is what has bitten, twice. Hardcoding the ELF soname made the
|
|
15
|
+
// whole composite-template API unavailable on macOS: `libgtk-4.so.1` does not
|
|
16
|
+
// exist there, so every `registerClass({ Template })` widget failed with "the
|
|
17
|
+
// libgtk-4 template API is unavailable" on a host with GTK 4 correctly installed.
|
|
18
|
+
// Invisible until v0.27.0 shipped the first darwin-x64 addon.
|
|
19
|
+
#if defined(_WIN32)
|
|
20
|
+
// gvsbuild's leaf — what @gjsify/gtk-runtime-win32-x64 ships — then MSYS2's
|
|
21
|
+
// `lib`-prefixed spelling.
|
|
22
|
+
constexpr const char* kGtkLeaves[] = {"gtk-4-1.dll", "libgtk-4-1.dll"};
|
|
23
|
+
using LibHandle = HMODULE;
|
|
24
|
+
|
|
25
|
+
// The counterpart of RTLD_NOLOAD, and it is load-bearing rather than an
|
|
26
|
+
// optimisation: `requireGi('Gtk','4.0')` has already loaded the DLL through the
|
|
27
|
+
// typelib's shared_library field, and asking for a handle to THAT copy is what
|
|
28
|
+
// keeps this from pulling a second GTK off PATH.
|
|
29
|
+
inline LibHandle OpenAlreadyLoaded(const char* leaf) { return GetModuleHandleA(leaf); }
|
|
30
|
+
inline LibHandle OpenLibrary(const char* leaf) { return LoadLibraryA(leaf); }
|
|
31
|
+
inline void* FindSymbol(LibHandle lib, const char* name) {
|
|
32
|
+
return reinterpret_cast<void*>(GetProcAddress(lib, name));
|
|
33
|
+
}
|
|
34
|
+
#else
|
|
35
|
+
#if defined(__APPLE__)
|
|
36
|
+
constexpr const char* kGtkLeaves[] = {"libgtk-4.1.dylib", "libgtk-4.dylib"};
|
|
37
|
+
#else
|
|
38
|
+
constexpr const char* kGtkLeaves[] = {"libgtk-4.so.1", "libgtk-4.so"};
|
|
39
|
+
#endif
|
|
40
|
+
using LibHandle = void*;
|
|
41
|
+
|
|
42
|
+
// RTLD_NOLOAD first — requireGi('Gtk','4.0') already dlopened libgtk-4 via the
|
|
43
|
+
// typelib, so this only bumps the refcount; the plain dlopen behind it serves a
|
|
44
|
+
// caller that never required Gtk through the typelib.
|
|
45
|
+
inline LibHandle OpenAlreadyLoaded(const char* leaf) {
|
|
46
|
+
return dlopen(leaf, RTLD_LAZY | RTLD_NOLOAD);
|
|
47
|
+
}
|
|
48
|
+
inline LibHandle OpenLibrary(const char* leaf) { return dlopen(leaf, RTLD_LAZY); }
|
|
49
|
+
inline void* FindSymbol(LibHandle lib, const char* name) { return dlsym(lib, name); }
|
|
50
|
+
#endif
|
|
51
|
+
|
|
52
|
+
} // namespace
|
|
53
|
+
|
|
8
54
|
// Resolve the GTK template API once (C++11 function-local static init is
|
|
9
|
-
// thread-safe; node-gi calls these only on the main thread).
|
|
10
|
-
//
|
|
11
|
-
//
|
|
55
|
+
// thread-safe; node-gi calls these only on the main thread).
|
|
56
|
+
//
|
|
57
|
+
// WINDOWS USED TO BE A STUB HERE — an `#ifdef _WIN32 → return &api` leaving
|
|
58
|
+
// `api.ok` false, on the reasoning that "GTK on Windows is Phase 2". The
|
|
59
|
+
// reasoning went stale without the stub noticing: the `--windowing` runtime
|
|
60
|
+
// bundle now ships GTK and libadwaita for win32-x64 and CI renders the whole
|
|
61
|
+
// Libadwaita gallery on it, while `gjsify showcase three-geometry-teapot
|
|
62
|
+
// --runtime node` still died on Windows with "the libgtk-4 template API is
|
|
63
|
+
// unavailable" — on a machine where GTK 4 was present and working. Nothing was
|
|
64
|
+
// missing but these nine symbols.
|
|
65
|
+
//
|
|
66
|
+
// Same lesson as the macOS soname bug, from the other side: a per-OS branch that
|
|
67
|
+
// cannot be EXECUTED anywhere is not a conservative default, it is an untested
|
|
68
|
+
// claim. So this function has no OS branch left — only a per-OS loader above it.
|
|
12
69
|
const GtkTemplateApi* GetGtkTemplateApi() {
|
|
13
70
|
static GtkTemplateApi api = {};
|
|
14
71
|
static bool initialised = false;
|
|
15
72
|
if (initialised) return &api;
|
|
16
73
|
initialised = true;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// only. GTK on Windows is Phase 2; the Phase-1 Windows CI proves the display-
|
|
20
|
-
// free core, which never exercises templates. api.ok stays false → template
|
|
21
|
-
// callers warn + no-op / throw a clear "template API unavailable" error.
|
|
22
|
-
return &api;
|
|
23
|
-
#else
|
|
24
|
-
// The library's LEAF NAME IS PER-OS, and hardcoding the ELF soname made the
|
|
25
|
-
// whole composite-template API unavailable on macOS: `libgtk-4.so.1` does not
|
|
26
|
-
// exist there, so every `registerClass({ Template })` widget failed with
|
|
27
|
-
// "the libgtk-4 template API is unavailable" on a host with GTK 4 correctly
|
|
28
|
-
// installed. Invisible until v0.27.0 shipped the first darwin-x64 addon.
|
|
29
|
-
//
|
|
30
|
-
// Candidates are the leaf names GTK 4 actually installs, newest ABI first.
|
|
31
|
-
#ifdef __APPLE__
|
|
32
|
-
static const char* const kGtkLeaves[] = {"libgtk-4.1.dylib", "libgtk-4.dylib"};
|
|
33
|
-
#else
|
|
34
|
-
static const char* const kGtkLeaves[] = {"libgtk-4.so.1", "libgtk-4.so"};
|
|
35
|
-
#endif
|
|
36
|
-
void* lib = nullptr;
|
|
74
|
+
|
|
75
|
+
LibHandle lib = nullptr;
|
|
37
76
|
for (const char* leaf : kGtkLeaves) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// caller that never required Gtk through the typelib.
|
|
41
|
-
lib = dlopen(leaf, RTLD_LAZY | RTLD_NOLOAD);
|
|
42
|
-
if (lib == nullptr) lib = dlopen(leaf, RTLD_LAZY);
|
|
77
|
+
lib = OpenAlreadyLoaded(leaf);
|
|
78
|
+
if (lib == nullptr) lib = OpenLibrary(leaf);
|
|
43
79
|
if (lib != nullptr) break;
|
|
44
80
|
}
|
|
45
81
|
if (lib == nullptr) return &api; // api.ok stays false → callers warn + no-op
|
|
46
82
|
api.set_template = reinterpret_cast<decltype(api.set_template)>(
|
|
47
|
-
|
|
83
|
+
FindSymbol(lib, "gtk_widget_class_set_template"));
|
|
48
84
|
api.set_template_from_resource = reinterpret_cast<decltype(api.set_template_from_resource)>(
|
|
49
|
-
|
|
85
|
+
FindSymbol(lib, "gtk_widget_class_set_template_from_resource"));
|
|
50
86
|
api.bind_template_child_full = reinterpret_cast<decltype(api.bind_template_child_full)>(
|
|
51
|
-
|
|
52
|
-
api.set_css_name =
|
|
53
|
-
|
|
87
|
+
FindSymbol(lib, "gtk_widget_class_bind_template_child_full"));
|
|
88
|
+
api.set_css_name = reinterpret_cast<decltype(api.set_css_name)>(
|
|
89
|
+
FindSymbol(lib, "gtk_widget_class_set_css_name"));
|
|
54
90
|
api.init_template =
|
|
55
|
-
reinterpret_cast<decltype(api.init_template)>(
|
|
91
|
+
reinterpret_cast<decltype(api.init_template)>(FindSymbol(lib, "gtk_widget_init_template"));
|
|
56
92
|
api.get_template_child = reinterpret_cast<decltype(api.get_template_child)>(
|
|
57
|
-
|
|
93
|
+
FindSymbol(lib, "gtk_widget_get_template_child"));
|
|
58
94
|
api.set_template_scope = reinterpret_cast<decltype(api.set_template_scope)>(
|
|
59
|
-
|
|
95
|
+
FindSymbol(lib, "gtk_widget_class_set_template_scope"));
|
|
60
96
|
api.builder_get_current_object = reinterpret_cast<decltype(api.builder_get_current_object)>(
|
|
61
|
-
|
|
97
|
+
FindSymbol(lib, "gtk_builder_get_current_object"));
|
|
62
98
|
api.builder_scope_get_type = reinterpret_cast<decltype(api.builder_scope_get_type)>(
|
|
63
|
-
|
|
99
|
+
FindSymbol(lib, "gtk_builder_scope_get_type"));
|
|
64
100
|
api.ok = api.set_template != nullptr && api.set_template_from_resource != nullptr &&
|
|
65
101
|
api.bind_template_child_full != nullptr && api.set_css_name != nullptr &&
|
|
66
102
|
api.init_template != nullptr && api.get_template_child != nullptr;
|
|
67
103
|
return &api;
|
|
68
|
-
#endif // _WIN32
|
|
69
104
|
}
|
|
70
105
|
|
|
71
106
|
// The live JS env stamped on a template-callback scope (refreshed each construct).
|