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/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<a>
|
|
3
3
|
<img
|
|
4
4
|
alt="NODE-GTK"
|
|
5
|
-
width="
|
|
5
|
+
width="200"
|
|
6
6
|
src="https://raw.githubusercontent.com/romgrk/node-gtk/master/img/node-gtk-logo.svg?sanitize=true"
|
|
7
7
|
/>
|
|
8
8
|
</a>
|
|
@@ -12,205 +12,89 @@
|
|
|
12
12
|
<p align="center">
|
|
13
13
|
<b>GTK bindings for NodeJS</b>
|
|
14
14
|
<br/>
|
|
15
|
-
<img src="https://img.shields.io/npm/v/node-gtk" alt="Package Version" />
|
|
16
15
|
</p>
|
|
17
16
|
|
|
18
|
-
`node-gtk` is a [gobject-introspection](https://gi.readthedocs.io/en/latest) library
|
|
19
|
-
for nodejs. It makes it possible to use any introspected C library, such as GTK,
|
|
20
|
-
usable. It is similar in essence to [GJS](https://wiki.gnome.org/action/show/Projects/Gjs)
|
|
21
|
-
or [PyGObject](https://pygobject.readthedocs.io). Please note this project is
|
|
22
|
-
currently in a _alpha_ state.
|
|
23
|
-
|
|
24
|
-
Supported Node.js versions: **20**, **22**, **24** (other versions may work but are untested)<br>
|
|
25
|
-
Supported platforms:
|
|
26
|
-
- **Linux** — prebuilt binaries available
|
|
27
|
-
- **macOS** — prebuilt binaries available
|
|
28
|
-
- **Windows** — prebuilt binaries available (but read [Windows](#windows))
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
### Table of contents
|
|
32
|
-
|
|
33
|
-
- [Usage](#usage)
|
|
34
|
-
- [ES modules](#es-modules)
|
|
35
|
-
- [Documentation](#documentation)
|
|
36
|
-
- [TypeScript](#typescript)
|
|
37
|
-
- [Installing](#installing)
|
|
38
|
-
- [Contributing](#contributing)
|
|
39
|
-
|
|
40
|
-
## Usage
|
|
41
|
-
|
|
42
|
-
Below is a [minimal example](./examples/hello-world.js) of how to use node-gtk:
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
const gi = require('node-gtk');
|
|
46
|
-
const GLib = gi.require('GLib', '2.0');
|
|
47
|
-
const Gtk = gi.require('Gtk', '4.0');
|
|
48
|
-
const Adw = gi.require('Adw', '1');
|
|
49
|
-
|
|
50
|
-
const loop = GLib.MainLoop.new(null, false);
|
|
51
|
-
const app = new Adw.Application('com.github.romgrk.node-gtk.hello', 0);
|
|
52
|
-
|
|
53
|
-
app.on('activate', () => {
|
|
54
|
-
const content = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
|
55
|
-
content.append(new Adw.HeaderBar());
|
|
56
|
-
content.append(new Gtk.Label({ label: 'Hello Adwaita!', vexpand: true }));
|
|
57
|
-
|
|
58
|
-
const window = new Adw.ApplicationWindow(app);
|
|
59
|
-
window.setTitle('node-gtk');
|
|
60
|
-
window.setDefaultSize(300, 120);
|
|
61
|
-
window.setContent(content);
|
|
62
|
-
window.on('close-request', () => (loop.quit(), app.quit(), false));
|
|
63
|
-
window.present();
|
|
64
|
-
|
|
65
|
-
gi.startLoop();
|
|
66
|
-
loop.run();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
process.exit(app.run([]));
|
|
70
|
-
```
|
|
71
|
-
|
|
72
17
|
<p align="center">
|
|
73
|
-
<
|
|
18
|
+
<a href="#usage">Usage</a> · <a href="#installing">Installing</a> · <a href="./doc/index.md">Documentation</a> · <a href="#contributing">Contributing</a>
|
|
74
19
|
</p>
|
|
75
20
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
[A web browser (using WebKit2GTK)](./examples/browser.js)
|
|
79
|
-
|
|
80
|
-
<p align="center">
|
|
81
|
-
<img src="./img/browser.png" style="max-width: 500px; height: auto;"/>
|
|
82
|
-
</p>
|
|
21
|
+
<br />
|
|
83
22
|
|
|
84
|
-
|
|
23
|
+
`node-gtk` lets you build native GTK apps on **linux**, **macOS** and **windows**
|
|
24
|
+
with full **ESM**, **TypeScript** and **CSS hot-reload** support. Prebuilt binaries
|
|
25
|
+
are available for Node.js versions **22**, **24** and **26**.
|
|
85
26
|
|
|
86
27
|
<p align="center">
|
|
87
|
-
<img src="./img/
|
|
28
|
+
<img src="./img/browser.png" style="max-width: 500px; height: auto;" alt="A web browser build with node-gtk" />
|
|
88
29
|
</p>
|
|
89
30
|
|
|
90
|
-
##
|
|
91
|
-
|
|
92
|
-
The Usage example above is CommonJS. node-gtk also works under ESM, but the
|
|
93
|
-
blocking main-loop calls (`GLib.MainLoop.run`, `Gio`/`Gtk.Application.run`,
|
|
94
|
-
`Gtk.main`) **return immediately** instead of blocking and **don't return a
|
|
95
|
-
value** — so make the run call the last statement and exit from your handler:
|
|
96
|
-
|
|
97
|
-
```javascript
|
|
98
|
-
app.on('activate', () => {
|
|
99
|
-
// ...build the window...
|
|
100
|
-
window.on('close-request', () => (loop.quit(), app.quit(), false));
|
|
101
|
-
window.present();
|
|
102
|
-
|
|
103
|
-
gi.startLoop();
|
|
104
|
-
loop.run(); // returns immediately under ESM; do cleanup/exit in the handler
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
app.run([]); // not `process.exit(app.run([]))` — the return value is unavailable
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
CommonJS (and signal callbacks) are unaffected. For the why and the design
|
|
111
|
-
trade-off, see [#449](https://github.com/romgrk/node-gtk/issues/449).
|
|
112
|
-
|
|
113
|
-
## Documentation
|
|
114
|
-
|
|
115
|
-
[Read our documentation here](./doc/index.md)
|
|
116
|
-
|
|
117
|
-
## TypeScript
|
|
31
|
+
## Usage
|
|
118
32
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
the types always match your actual library versions and node-gtk's own runtime
|
|
122
|
-
shape (camelCase methods, signal callbacks, nullability, etc.).
|
|
33
|
+
The **create** tool generates a complete, ready-to-run GTK/Adwaita project, so you
|
|
34
|
+
can start building immediately after [installing GTK4](#installing):
|
|
123
35
|
|
|
124
36
|
```sh
|
|
125
|
-
|
|
126
|
-
npx node-gtk generate-types Gtk-4.0 Adw-1
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
The command emits one declaration file per namespace (plus the full dependency
|
|
130
|
-
closure) and a `node-gtk.d.ts` shim. Point your `tsconfig.json` at it:
|
|
131
|
-
|
|
132
|
-
```jsonc
|
|
133
|
-
{
|
|
134
|
-
"compilerOptions": {
|
|
135
|
-
"moduleResolution": "node16",
|
|
136
|
-
"paths": { "node-gtk": ["./node_modules/.node-gtk-types/node-gtk.d.ts"] }
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Then `gi.require` is fully typed — the namespace is inferred from the string
|
|
142
|
-
arguments:
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
import * as gi from 'node-gtk'
|
|
146
|
-
|
|
147
|
-
const Gtk = gi.require('Gtk', '4.0') // typed as the Gtk-4.0 namespace
|
|
148
|
-
const win = new Gtk.ApplicationWindow({ title: 'Hello', defaultWidth: 400 })
|
|
149
|
-
win.on('close-request', () => false) // signal name + callback are typed
|
|
37
|
+
npx node-gtk create <your-app>
|
|
150
38
|
```
|
|
151
39
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return value, and cross-namespace types. GNOME's API documentation is included
|
|
156
|
-
as JSDoc (with `@param`/`@returns`), so editors show it on hover — this reads the
|
|
157
|
-
`.gir` files installed by the libraries' `-dev`/`-devel` packages; pass
|
|
158
|
-
`--no-docs` for leaner output if they aren't installed or you don't want them.
|
|
159
|
-
|
|
160
|
-
Because the output is a generated cache under `node_modules`, add a `postinstall`
|
|
161
|
-
script so it regenerates on install:
|
|
162
|
-
|
|
163
|
-
```json
|
|
164
|
-
{ "scripts": { "postinstall": "node-gtk generate-types Gtk-4.0 Adw-1" } }
|
|
165
|
-
```
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="./img/create-app-example.png" style="width: 500px; height: auto;"/>
|
|
42
|
+
</p>
|
|
166
43
|
|
|
167
|
-
|
|
44
|
+
Also see our [hello world](./examples/hello-world.mjs), [web browser](./examples/browser.mjs)
|
|
45
|
+
or [system monitor](./examples/system-monitor.mjs) examples.
|
|
168
46
|
|
|
169
47
|
## Installing
|
|
170
48
|
|
|
171
|
-
|
|
172
|
-
2. Install the native libraries you use (see examples per platform below)
|
|
49
|
+
There are two steps:
|
|
173
50
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
# This installs a prebuilt binary when one is available for your platform and
|
|
178
|
-
# Node.js version, otherwise it falls back to building from source.
|
|
179
|
-
```
|
|
51
|
+
1. Install `node-gtk` itself (*done by the create tool*)
|
|
52
|
+
2. Install the native libraries you use (see examples per platform below)
|
|
180
53
|
|
|
181
54
|
#### Linux
|
|
182
55
|
|
|
183
56
|
```sh
|
|
184
57
|
# archlinux
|
|
185
|
-
pacman -S gtk4
|
|
58
|
+
pacman -S gtk4 libadwaita
|
|
59
|
+
|
|
60
|
+
# fedora
|
|
61
|
+
dnf install gtk4 libadwaita
|
|
186
62
|
|
|
187
63
|
# ubuntu
|
|
188
|
-
|
|
64
|
+
# Already installed :)
|
|
189
65
|
```
|
|
190
66
|
|
|
191
67
|
#### macOS
|
|
192
68
|
|
|
193
69
|
```sh
|
|
194
|
-
brew install gtk4
|
|
70
|
+
brew install gtk4 libadwaita adwaita-icon-theme
|
|
195
71
|
```
|
|
196
72
|
|
|
197
73
|
#### Windows
|
|
198
74
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
75
|
+
```sh
|
|
76
|
+
# Already installed :)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> [!NOTE]
|
|
80
|
+
> Windows doesn't have the dependencies we need in a package manager, therefore
|
|
81
|
+
> `node-gtk` ships prebuilt versions of GTK 4 / Adwaita, so `npm install node-gtk`
|
|
82
|
+
> is all you need **if** your dependency is in our
|
|
83
|
+
> [list of prebuilt libraries](./windows/runtime-libraries.txt).
|
|
203
84
|
|
|
204
85
|
### build from source
|
|
205
86
|
|
|
206
|
-
Building from source, or contributing? See [Building from source](./doc/building.md).
|
|
87
|
+
Building from source, or [contributing](./doc/contributing.md)? See [Building from source](./doc/building.md).
|
|
207
88
|
|
|
208
|
-
##
|
|
89
|
+
## Documentation
|
|
90
|
+
|
|
91
|
+
[Read our documentation here](./doc/index.md)
|
|
92
|
+
|
|
93
|
+
## Other notes
|
|
209
94
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
95
|
+
`node-gtk` is a [gobject-introspection](https://gi.readthedocs.io/en/latest) library
|
|
96
|
+
for nodejs. It makes it possible to use any introspected C library, such as GTK,
|
|
97
|
+
usable. It is similar in essence to [GJS](https://wiki.gnome.org/action/show/Projects/Gjs)
|
|
98
|
+
or [PyGObject](https://pygobject.readthedocs.io).
|
|
213
99
|
|
|
214
|
-
|
|
215
|
-
- https://v8docs.nodesource.com/
|
|
216
|
-
- https://github.com/nodejs/nan#api
|
|
100
|
+
[MIT License](./LICENSE)
|
package/bin/node-gtk.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Subcommands:
|
|
6
6
|
* generate-types Generate TypeScript declarations from the installed typelibs.
|
|
7
|
+
* create Create a new GTK/Adwaita application.
|
|
8
|
+
* list List the GObject-Introspection libraries available locally.
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
11
|
const cmd = process.argv[2]
|
|
@@ -12,6 +14,13 @@ switch (cmd) {
|
|
|
12
14
|
case 'generate-types':
|
|
13
15
|
require('../tools/generate-types.js').run(process.argv.slice(3))
|
|
14
16
|
break
|
|
17
|
+
case 'create':
|
|
18
|
+
require('../tools/create-app.js').run(process.argv.slice(3))
|
|
19
|
+
break
|
|
20
|
+
case 'list':
|
|
21
|
+
case 'list-libraries':
|
|
22
|
+
require('../tools/list-libraries.js').run(process.argv.slice(3))
|
|
23
|
+
break
|
|
15
24
|
case undefined:
|
|
16
25
|
case '-h':
|
|
17
26
|
case '--help':
|
|
@@ -20,9 +29,11 @@ switch (cmd) {
|
|
|
20
29
|
Usage: node-gtk <command> [options]
|
|
21
30
|
|
|
22
31
|
Commands:
|
|
32
|
+
create <directory> Create a new GTK/Adwaita app
|
|
23
33
|
generate-types <Namespace-Version> [...] Generate TypeScript types (.d.ts)
|
|
34
|
+
list [filter] List available libraries & versions
|
|
24
35
|
|
|
25
|
-
Run \`node-gtk
|
|
36
|
+
Run \`node-gtk <command> --help\` for details.`)
|
|
26
37
|
process.exit(cmd ? 0 : 1)
|
|
27
38
|
break
|
|
28
39
|
default:
|
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",
|
|
Binary file
|
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)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* hooks.mjs — Node.js ESM module-customization hooks for the `gi:` scheme.
|
|
3
|
+
*
|
|
4
|
+
* Enables `import Gtk from 'gi:Gtk-4.0'`, where the default export is the
|
|
5
|
+
* namespace object returned by node-gtk's `gi.require('Gtk', '4.0')`. Members are
|
|
6
|
+
* read off that object: `const { Box, Label } = Gtk`.
|
|
7
|
+
*
|
|
8
|
+
* Install them with `node --import node-gtk/register app.mjs` (see register.mjs).
|
|
9
|
+
*
|
|
10
|
+
* The hooks run on a separate loader thread, so they do NO native work: `load`
|
|
11
|
+
* only emits a tiny synthetic ES module whose body calls `gi.require` on the
|
|
12
|
+
* main thread when the module is evaluated. Requires Node >= 20.6 (module.register).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const PREFIX = 'gi:'
|
|
16
|
+
|
|
17
|
+
/* Absolute file:// URL to lib/index.js, embedded into the generated source. The
|
|
18
|
+
* synthetic module's parent URL is the schemeless `gi:` URL, which has no
|
|
19
|
+
* filesystem base, so a bare `import 'node-gtk'` could not be resolved from it —
|
|
20
|
+
* the absolute URL sidesteps resolution entirely. */
|
|
21
|
+
const INDEX_URL = new URL('../index.js', import.meta.url).href
|
|
22
|
+
|
|
23
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
24
|
+
if (specifier.startsWith(PREFIX))
|
|
25
|
+
return { url: specifier, shortCircuit: true }
|
|
26
|
+
return nextResolve(specifier, context)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function load(url, context, nextLoad) {
|
|
30
|
+
if (!url.startsWith(PREFIX))
|
|
31
|
+
return nextLoad(url, context)
|
|
32
|
+
|
|
33
|
+
// `gi:Gtk-4.0` -> ('Gtk', '4.0'); `gi:Adw-1` -> ('Adw', '1'); `gi:cairo` -> ('cairo', null).
|
|
34
|
+
// Split on the first '-' only: GI namespace names never contain '-', versions may.
|
|
35
|
+
const spec = url.slice(PREFIX.length)
|
|
36
|
+
const dash = spec.indexOf('-')
|
|
37
|
+
const name = dash === -1 ? spec : spec.slice(0, dash)
|
|
38
|
+
const version = dash === -1 ? null : spec.slice(dash + 1)
|
|
39
|
+
|
|
40
|
+
const call = version === null
|
|
41
|
+
? `gi.require(${JSON.stringify(name)})`
|
|
42
|
+
: `gi.require(${JSON.stringify(name)}, ${JSON.stringify(version)})`
|
|
43
|
+
|
|
44
|
+
const source =
|
|
45
|
+
`import gi from ${JSON.stringify(INDEX_URL)};\n` +
|
|
46
|
+
`export default ${call};\n`
|
|
47
|
+
|
|
48
|
+
return { format: 'module', shortCircuit: true, source }
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* register.mjs — install the `gi:` import hooks.
|
|
3
|
+
*
|
|
4
|
+
* Usage: node --import node-gtk/register app.mjs
|
|
5
|
+
*
|
|
6
|
+
* Then, in app.mjs:
|
|
7
|
+
* import Gtk from 'gi:Gtk-4.0'
|
|
8
|
+
* const { Box, Label } = Gtk
|
|
9
|
+
*
|
|
10
|
+
* Note: hooks only affect imports evaluated *after* registration. To use a static
|
|
11
|
+
* `import ... from 'gi:...'` in your entry module, register via the `--import`
|
|
12
|
+
* flag above (not a programmatic `import 'node-gtk/register'` in that same file).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { register } from 'node:module'
|
|
16
|
+
|
|
17
|
+
register(new URL('./hooks.mjs', import.meta.url))
|
package/lib/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const moduleCache = internal.GetModuleCache()
|
|
|
8
8
|
// Must be loaded first, to setup the GI functions
|
|
9
9
|
const bootstrap = require('./bootstrap.js')
|
|
10
10
|
const module_ = require('./module.js')
|
|
11
|
-
|
|
11
|
+
require('./loop.js') // installs the automatic main-loop integration
|
|
12
12
|
const registerClass = require('./register-class.js')
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -42,7 +42,6 @@ function getGType(value) {
|
|
|
42
42
|
module.exports = {
|
|
43
43
|
// Public API
|
|
44
44
|
...module_,
|
|
45
|
-
startLoop: loop.start,
|
|
46
45
|
registerClass: registerClass,
|
|
47
46
|
getGType: getGType,
|
|
48
47
|
System: internal.System,
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* index.mjs
|
|
3
|
+
*
|
|
4
|
+
* ESM facade over the CommonJS entry (index.js), so that named imports work:
|
|
5
|
+
*
|
|
6
|
+
* import gi, { require, registerClass } from 'node-gtk'
|
|
7
|
+
*
|
|
8
|
+
* Node's CommonJS-to-ESM named-export detection (cjs-module-lexer) cannot see
|
|
9
|
+
* through index.js's computed `module.exports`, so we re-export explicitly here.
|
|
10
|
+
* Both this file and `require('node-gtk')` share the same underlying index.js
|
|
11
|
+
* instance (Node caches it by path), so there is no duplicated state.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import gi from './index.js'
|
|
15
|
+
|
|
16
|
+
export default gi
|
|
17
|
+
|
|
18
|
+
export const require = gi.require
|
|
19
|
+
export const isLoaded = gi.isLoaded
|
|
20
|
+
export const prependSearchPath = gi.prependSearchPath
|
|
21
|
+
export const prependLibraryPath = gi.prependLibraryPath
|
|
22
|
+
export const listAvailableModules = gi.listAvailableModules
|
|
23
|
+
export const registerClass = gi.registerClass
|
|
24
|
+
export const getGType = gi.getGType
|
|
25
|
+
export const System = gi.System
|
package/lib/inspect.js
CHANGED
package/lib/loop.js
CHANGED
|
@@ -58,6 +58,11 @@ function start() {
|
|
|
58
58
|
* @returns {*} the native return value, or undefined when deferred
|
|
59
59
|
*/
|
|
60
60
|
function runLoopEntry(run) {
|
|
61
|
+
// The loop integration must be active before we block in a native main loop,
|
|
62
|
+
// so start it automatically on the first run. Calling startLoop() explicitly
|
|
63
|
+
// still works and is no longer required (start() is idempotent).
|
|
64
|
+
start()
|
|
65
|
+
|
|
61
66
|
if (internal.IsRunningMicrotasks()) {
|
|
62
67
|
setImmediate(run)
|
|
63
68
|
return undefined
|
package/lib/module.js
CHANGED
|
@@ -129,6 +129,12 @@ function listAvailableModules() {
|
|
|
129
129
|
// Helpers
|
|
130
130
|
|
|
131
131
|
function parseModuleFilename(filename) {
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
// Typelibs are named `Name-Version.typelib`; the version is the trailing
|
|
133
|
+
// `-X.Y`, so split on the LAST dash — namespaces themselves may contain dashes
|
|
134
|
+
// (e.g. `GUPnP-DLNA-2.0` -> name `GUPnP-DLNA`, version `2.0`).
|
|
135
|
+
const base = filename.replace(/\.typelib$/, '')
|
|
136
|
+
const dash = base.lastIndexOf('-')
|
|
137
|
+
if (dash === -1)
|
|
138
|
+
return { name: base, version: '' }
|
|
139
|
+
return { name: base.slice(0, dash), version: base.slice(dash + 1) }
|
|
134
140
|
}
|
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) {
|