@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 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.32.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). How the library
10
- // handle is obtained — and why the leaf name has to be per-OS — is documented at
11
- // the dlopen below.
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
- #ifdef _WIN32
18
- // The Gtk.Widget composite-template API is resolved lazily via dlsym on POSIX
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
- // RTLD_NOLOAD first — requireGi('Gtk','4.0') already dlopened libgtk-4 via the
39
- // typelib, so this only bumps the refcount; the plain dlopen behind it serves a
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
- dlsym(lib, "gtk_widget_class_set_template"));
83
+ FindSymbol(lib, "gtk_widget_class_set_template"));
48
84
  api.set_template_from_resource = reinterpret_cast<decltype(api.set_template_from_resource)>(
49
- dlsym(lib, "gtk_widget_class_set_template_from_resource"));
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
- dlsym(lib, "gtk_widget_class_bind_template_child_full"));
52
- api.set_css_name =
53
- reinterpret_cast<decltype(api.set_css_name)>(dlsym(lib, "gtk_widget_class_set_css_name"));
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)>(dlsym(lib, "gtk_widget_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
- dlsym(lib, "gtk_widget_get_template_child"));
93
+ FindSymbol(lib, "gtk_widget_get_template_child"));
58
94
  api.set_template_scope = reinterpret_cast<decltype(api.set_template_scope)>(
59
- dlsym(lib, "gtk_widget_class_set_template_scope"));
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
- dlsym(lib, "gtk_builder_get_current_object"));
97
+ FindSymbol(lib, "gtk_builder_get_current_object"));
62
98
  api.builder_scope_get_type = reinterpret_cast<decltype(api.builder_scope_get_type)>(
63
- dlsym(lib, "gtk_builder_scope_get_type"));
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).