node-gtk 0.14.0 → 2.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 CHANGED
@@ -16,253 +16,143 @@
16
16
  </p>
17
17
 
18
18
  Node-Gtk is a [gobject-introspection](https://gi.readthedocs.io/en/latest) library for nodejs. It makes it possible to
19
- use any introspected library, such as Gtk+, usable. It is similar in essence to [GJS](https://wiki.gnome.org/action/show/Projects/Gjs) or [PyGObject](https://pygobject.readthedocs.io). Please note this project is currently in a _beta_ state and is being developed. Any contributors willing to help
19
+ use any introspected library, such as Gtk+, usable. It is similar in essence to [GJS](https://wiki.gnome.org/action/show/Projects/Gjs) or [PyGObject](https://pygobject.readthedocs.io). Please note this project is currently in a _beta_ state and is being developed. Any contributors willing to help
20
20
  will be welcomed.
21
21
 
22
- Supported Node.js versions: **16**, **18** (other versions should work but are untested)<br>
23
- Pre-built binaries available for: **Linux**, **macOS** (all supported versions except 18)
22
+ Supported Node.js versions: **20**, **22**, **24** (other versions may work but are untested)<br>
23
+ Pre-built binaries available for: **Linux**, **macOS**
24
24
 
25
25
  ### Table of contents
26
26
 
27
27
  - [Usage](#usage)
28
28
  - [Documentation](#documentation)
29
+ - [TypeScript](#typescript)
29
30
  - [Installing and building](#installing-and-building)
30
- - [Target Platforms](#target-platforms)
31
- - [Requirements](#requirements)
32
- - [How to build on Ubuntu](#how-to-build-on-ubuntu)
33
- - [How to build on Fedora](#how-to-build-on-fedora)
34
- - [How to build on ArchLinux](#how-to-build-on-archlinux)
35
- - [How to build on macOS](#how-to-build-on-macos)
36
- - [How to build on Windows](#how-to-build-on-windows)
37
- - [Testing the project](#testing-the-project)
38
- - [Browser demo](#browser-demo)
39
31
  - [Contributing](#contributing)
40
32
 
41
33
  ## Usage
42
34
 
43
- Below is a minimal example of how to use the code, but take a look at
44
- our [template](https://github.com/romgrk/node-gtk-template) or at
45
- [react-gtk](https://github.com/codejamninja/react-gtk) to bootstrap your
46
- project.
35
+ Below is a [minimal example](./examples/hello-world.js) of how to use node-gtk:
47
36
 
48
37
  ```javascript
49
- const gi = require('node-gtk')
50
- const Gtk = gi.require('Gtk', '3.0')
51
-
52
- gi.startLoop()
53
- Gtk.init()
38
+ const gi = require('node-gtk');
39
+ const GLib = gi.require('GLib', '2.0');
40
+ const Gtk = gi.require('Gtk', '4.0');
41
+ const Adw = gi.require('Adw', '1');
42
+
43
+ const loop = GLib.MainLoop.new(null, false);
44
+ const app = new Adw.Application('com.github.romgrk.node-gtk.hello', 0);
45
+
46
+ app.on('activate', () => {
47
+ const content = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
48
+ content.append(new Adw.HeaderBar());
49
+ content.append(new Gtk.Label({ label: 'Hello Adwaita!', vexpand: true }));
50
+
51
+ const window = new Adw.ApplicationWindow(app);
52
+ window.setTitle('node-gtk');
53
+ window.setDefaultSize(300, 120);
54
+ window.setContent(content);
55
+ window.on('close-request', () => (loop.quit(), app.quit(), false));
56
+ window.present();
57
+
58
+ gi.startLoop();
59
+ loop.run();
60
+ });
61
+
62
+ process.exit(app.run([]));
63
+ ```
54
64
 
55
- const win = new Gtk.Window()
56
- win.on('destroy', () => Gtk.mainQuit())
57
- win.on('delete-event', () => false)
65
+ <p align="center">
66
+ <img src="./img/hello-world.png" style="width: 290px; height: auto;"/>
67
+ </p>
58
68
 
59
- win.setDefaultSize(200, 80)
60
- win.add(new Gtk.Label({ label: 'Hello Gtk+' }))
69
+ You can also easily create custom applications:
61
70
 
62
- win.showAll()
63
- Gtk.main()
64
- ```
71
+ [A web browser (using WebKit2GTK)](./examples/browser.js)
65
72
 
66
73
  <p align="center">
67
- <img src="./img/hello-node-gtk.png" alt="Hello Gtk" style="width: 220px; height: auto;"/>
74
+ <img src="./img/browser.png" style="max-width: 500px; height: auto;"/>
68
75
  </p>
69
76
 
70
- See our [examples](./examples) folder for more examples, and in particular the
71
- [browser demo source](https://github.com/romgrk/node-gtk/blob/master/examples/browser.js) for
72
- a more complex application.
77
+ [A system monitor](./examples/system-monitor.js)
73
78
 
74
79
  <p align="center">
75
- <img src="./img/browser.png" alt="Hello Gtk" style="max-width: 500px; height: auto;"/>
80
+ <img src="./img/system-monitor.png" style="width: 400px; height: auto;"/>
76
81
  </p>
77
82
 
83
+ #### Other projects
84
+
85
+ The [react-gtk](https://github.com/codejamninja/react-gtk) project may also allow you to use GTK via React (unmaintained).
78
86
 
79
87
  ## Documentation
80
88
 
81
89
  [Read our documentation here](./doc/index.md)
82
90
 
83
- ## Installing and building
84
-
85
- Note that prebuilt binaries are available for common systems, in those cases building is not necessary.
91
+ ## TypeScript
86
92
 
87
- ##### Target Platforms
88
-
89
- - **Linux**: prebuilt binaries available
90
- - **macOS**: prebuilt binaries available
91
- - **Windows**: no prebuilt binaries
92
-
93
- ### Requirements
94
-
95
- - `git`
96
- - `nodejs@10` or higher
97
- - `python3` (for `node-gyp`)
98
- - C compiler (`gcc@8` or higher, or `clang`)
99
-
100
- ### How to build on Ubuntu
101
-
102
- Install basic dependencies.
93
+ node-gtk can generate TypeScript declarations for the libraries you use,
94
+ straight from the GObject-Introspection typelibs installed on your machine — so
95
+ the types always match your actual library versions and node-gtk's own runtime
96
+ shape (camelCase methods, signal callbacks, nullability, etc.).
103
97
 
104
98
  ```sh
105
- sudo apt-get install \
106
- build-essential git \
107
- gobject-introspection \
108
- libgirepository1.0-dev \
109
- libcairo2 \
110
- libcairo2-dev
99
+ # generates ./node_modules/.node-gtk-types (a hidden, git-ignored cache)
100
+ npx node-gtk generate-types Gtk-4.0 Adw-1
111
101
  ```
112
102
 
113
- At this point `npm install node-gtk` should already install, fallback and build `node-gtk` without problems.
114
-
115
- ### How to build on Fedora
103
+ The command emits one declaration file per namespace (plus the full dependency
104
+ closure) and a `node-gtk.d.ts` shim. Point your `tsconfig.json` at it:
116
105
 
117
- Install basic dependencies:
118
-
119
- ```sh
120
- sudo dnf install \
121
- @development-tools \
122
- nodejs \
123
- gobject-introspection \
124
- gtk3 \
125
- cairo
106
+ ```jsonc
107
+ {
108
+ "compilerOptions": {
109
+ "moduleResolution": "node16",
110
+ "paths": { "node-gtk": ["./node_modules/.node-gtk-types/node-gtk.d.ts"] }
111
+ }
112
+ }
126
113
  ```
127
114
 
128
- After installing of packages, run `npm install node-gtk`.
115
+ Then `gi.require` is fully typed the namespace is inferred from the string
116
+ arguments:
129
117
 
130
- ### How to build on ArchLinux
118
+ ```ts
119
+ import * as gi from 'node-gtk'
131
120
 
132
- The following should be the bare minimum to be able to build the project.
133
-
134
- ```sh
135
- pacman -S --needed \
136
- base-devel git \
137
- nodejs npm \
138
- gtk3 gobject-introspection \
139
- cairo
121
+ const Gtk = gi.require('Gtk', '4.0') // typed as the Gtk-4.0 namespace
122
+ const win = new Gtk.ApplicationWindow({ title: 'Hello', defaultWidth: 400 })
123
+ win.on('close-request', () => false) // signal name + callback are typed
140
124
  ```
141
125
 
142
- Feel free to install all `base-devel` utilities.
143
-
144
- After installing those packages, `npm install node-gtk` would do.
145
-
146
- ### How to build on macOS
126
+ You get typed constructor properties (including inherited and interface ones),
127
+ camelCase methods with real return types, GI nullability, typed signal
128
+ overloads, enums, `bigint` for 64-bit integers, out-parameters surfaced as the
129
+ return value, and cross-namespace types. GNOME's API documentation is included
130
+ as JSDoc (with `@param`/`@returns`), so editors show it on hover — this reads the
131
+ `.gir` files installed by the libraries' `-dev`/`-devel` packages; pass
132
+ `--no-docs` for leaner output if they aren't installed or you don't want them.
147
133
 
148
- Assuming you have [brew](http://brew.sh) installed, the following has been successfully tested on El Captain.
134
+ Because the output is a generated cache under `node_modules`, add a `postinstall`
135
+ script so it regenerates on install:
149
136
 
150
- ```sh
151
- brew install git node gobject-introspection gtk+3 cairo
137
+ ```json
138
+ { "scripts": { "postinstall": "node-gtk generate-types Gtk-4.0 Adw-1" } }
152
139
  ```
153
140
 
154
- At this point `npm install node-gtk` should already install, fallback and build `node-gtk` without problems.
155
-
156
- ### How to build on Windows
157
-
158
- Mandatory dependency is Visual C++ Build Environment: Visual Studio Build Tools (using "Visual C++ build tools" workload) or Visual Studio Community (using the "Desktop development with C++" workload).
159
-
160
- The easiest/tested way to build this repository is within a _MinGW shell_ provided by the [MSYS2 installer](https://msys2.github.io/).
161
-
162
- Once VS and its C++ compiler is available and MSYS2 installed, launch the MinGW shell.
163
-
164
- ```sh
165
- # update the system
166
- # in case of errors, wait for the update to complete
167
- # then close and open again MingW shell
168
- pacman -Syyu --noconfirm
169
-
170
- # install git, gtk3 and extra dependencie
171
- pacman -S --needed --noconfirm git mingw-w64-$(uname -m)-{gtk3,gobject-introspection,pkg-config,cairo}
172
-
173
- # where to put the repository clone?
174
- # pick your flder or use ~/oss (Open Source Software)
175
- mkdir -p ~/oss/
176
- cd ~/oss
177
-
178
- # clone node-gtk there
179
- git clone https://github.com/romgrk/node-gtk
180
- cd node-gtk
181
-
182
- # don't include /mingw64/include directly since it conflicts with
183
- # Windows SDK headers. we copy needed headers to __extra__ directory:
184
- ./windows/mingw_include_extra.sh
141
+ Run `npx node-gtk generate-types --help` for options.
185
142
 
186
- # if MSYS2 is NOT installed in C:/msys64 run:
187
- export MINGW_WINDOWS_PATH=$(./windows/mingw_windows_path.sh)
188
-
189
- # first run might take a while
190
- GYP_MSVS_VERSION=2017 npm install
191
- ```
192
-
193
- The `GYP_MSVS_VERSION` could be 2017 or above.
194
- Please verify [which version you should use](https://github.com/nodejs/node-gyp#installation)
195
-
196
- The below blog post series will help you get started:
197
-
198
- 1. [Node.js GTK Hello World on Windows](https://ten0s.github.io/blog/2022/07/22/nodejs-gtk-hello-world-on-windows)
199
- 2. [Find DLLs and Typelibs dependencies for Node.js GTK Application on Windows](https://ten0s.github.io/blog/2022/07/25/find-dlls-and-typelibs-dependencies-for-nodejs-gtk-application-on-windows)
200
- 3. [Package Node.js GTK Application on Windows](https://ten0s.github.io/blog/2022/07/27/package-nodejs-gtk-application-on-windows)
201
-
202
- #### Possible issue on MinGW shell
203
-
204
- In case you are launching the general executable without knowing the correct platform,
205
- the binary path might not be available.
206
-
207
- In such case `python` won't be available either, and you can check via `which python` command.
208
-
209
- If not found, you need to export the platform related binary path:
210
-
211
- ```sh
212
- # example for the 32bit version
213
- export PATH="/mingw32/bin:$PATH"
214
- npm run install
215
- ```
216
-
217
- This should do the trick. You can also check if there is any python at all via `pacman -Qs python`.
218
-
219
- ### Testing the project
220
-
221
- If you'd like to test everything builds and work properly, after installing and building you can run any of the
222
- examples:
223
-
224
- ```sh
225
- node ./examples/hello-gtk.js
226
- ```
227
-
228
- If you'll see a little window saying hello that's it: it works!
229
-
230
- Please note in macOS the window doesn't automatically open above other windows.
231
- Try <kbd>Cmd</kbd> + <kbd>Tab</kbd> if you don't see it.
232
-
233
- #### Browser demo
234
-
235
- If you'd like to test `./examples/browser.js` you'll need [WebKit2 GTK+](http://webkitgtk.org/) libary.
236
-
237
- - in **Ubuntu**, you can `apt-get install libwebkit2gtk-3.0` (`4.0` works too) and try it out.
238
- - in **Fedora**, you should run `sudo dnf install webkit2gtk3`
239
- - in **ArchLinux**, you can `pacman -S --needed webkitgtk` and try it out.
240
- - in **macOS**, there is no way to run it right now because `webkitgtk` was removed from homebrew
241
-
242
- Once installed, you can `./examples/browser.js google.com` or any other page, and you might try the _dark theme_ out too:
143
+ ## Installing and building
243
144
 
244
- ```sh
245
- # macOS needs to have the Adwaita theme installed
246
- # brew install adwaita-icon-theme
247
-
248
- # Usage: ./examples/browser.js <url> [theme]
249
- ./examples/browser.js google.com dark
250
- ```
145
+ See [Installing & building](./doc/installation.md) for prebuilt-binary notes, per-platform build instructions (Linux, macOS, Windows), and how to run the tests and examples.
251
146
 
252
147
  ## Contributing
253
148
 
254
149
  If you'd like to help, we'd be more than happy to have support. To setup your development environment, you can
255
- run `npm run configure`. You can then build the project with `npm run build`.
256
-
257
- - https://developer.gnome.org/gi/stable/index.html
258
- - https://v8docs.nodesource.com/
259
- - https://github.com/nodejs/nan#api
260
-
261
- Don't hesitate to join our [Discord channel](https://discord.gg/r2VqPUV).
150
+ run `npm run configure`. You can then build the project with `npm run build`. To generate the `compile_commands.json`
151
+ for LSP to work nicely, you can use [bear](https://github.com/rizsotto/Bear) as `bear -- npm run build`.
262
152
 
263
- ### Contributors
153
+ - https://developer.gnome.org/gi/stable/index.html
154
+ - https://v8docs.nodesource.com/
155
+ - https://github.com/nodejs/nan#api
264
156
 
265
- - [magcius](https://github.com/magcius)
266
- - [WebReflection](https://github.com/WebReflection)
267
- - [romgrk](https://github.com/romgrk)
268
- - [wotzlaff](https://github.com/wotzlaff)
157
+ There is a [Discord channel](https://discord.gg/r2VqPUV) but it receives little monitoring, use github issues or
158
+ discussions preferably.
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * node-gtk CLI
4
+ *
5
+ * Subcommands:
6
+ * generate-types Generate TypeScript declarations from the installed typelibs.
7
+ */
8
+
9
+ const cmd = process.argv[2]
10
+
11
+ switch (cmd) {
12
+ case 'generate-types':
13
+ require('../tools/generate-types.js').run(process.argv.slice(3))
14
+ break
15
+ case undefined:
16
+ case '-h':
17
+ case '--help':
18
+ console.log(`node-gtk — GNOME GObject-Introspection bindings for Node.js
19
+
20
+ Usage: node-gtk <command> [options]
21
+
22
+ Commands:
23
+ generate-types <Namespace-Version> [...] Generate TypeScript types (.d.ts)
24
+
25
+ Run \`node-gtk generate-types --help\` for details.`)
26
+ process.exit(cmd ? 0 : 1)
27
+ break
28
+ default:
29
+ console.error(`node-gtk: unknown command '${cmd}'. Try 'node-gtk --help'.`)
30
+ process.exit(1)
31
+ }
package/lib/bootstrap.js CHANGED
@@ -82,11 +82,26 @@ function extendBaseClass(BaseClass) {
82
82
  }
83
83
 
84
84
  BaseClass.prototype.once = function once(event, callback, after) {
85
+ defineListeners(this)
86
+
87
+ if (!this._listeners.has(event))
88
+ this._listeners.set(event, new WeakMap())
89
+
90
+ const fnMap = this._listeners.get(event)
91
+
85
92
  const newCallback = (...args) => {
86
- callback(...args)
87
- this.off(event, newCallback)
93
+ this.off(event, callback)
94
+ return callback(...args)
95
+ }
96
+
97
+ const handlerID = this.connect(event, newCallback, after)
98
+ if (handlerID === 0) {
99
+ throw new Error(`Could not connect to signal ${event}`)
88
100
  }
89
- this.on(event, newCallback, after)
101
+ // Key the listener map by the user's original callback so that it can be
102
+ // cancelled with off(event, callback), even though the connected handler
103
+ // is the wrapper.
104
+ fnMap.set(callback, handlerID)
90
105
  return this
91
106
  }
92
107
 
@@ -220,7 +235,10 @@ function makeEnum(info) {
220
235
  for (let i = 0; i < nValues; i++) {
221
236
  const valueInfo = GI.enum_info_get_value(info, i);
222
237
  const valueName = getName(valueInfo).toUpperCase()
223
- const value = GI.value_info_get_value(valueInfo)
238
+ // g_value_info_get_value returns a gint64 (-> BigInt since #323), but enum
239
+ // and flags members are small integers and are compared/bitwise-combined
240
+ // as Numbers throughout, so coerce here.
241
+ const value = Number(GI.value_info_get_value(valueInfo))
224
242
  Object.defineProperty(object, valueName, {
225
243
  configurable: true,
226
244
  enumerable: true,
package/lib/index.js CHANGED
@@ -11,6 +11,30 @@ const module_ = require('./module.js')
11
11
  const loop = require('./loop.js')
12
12
  const registerClass = require('./register-class.js')
13
13
 
14
+ /**
15
+ * Returns the GType (as a BigInt) of a GObject/boxed class, an instance of one,
16
+ * or a GType passed through as-is. See #286.
17
+ *
18
+ * @param {Function|object|bigint} value a class, an instance, or a GType
19
+ * @returns {bigint} the associated GType
20
+ */
21
+ function getGType(value) {
22
+ if (typeof value === 'bigint')
23
+ return value
24
+
25
+ if (value != null) {
26
+ // A class: the GType lives on its prototype.
27
+ if (typeof value === 'function' && value.prototype != null && value.prototype.__gtype__ !== undefined)
28
+ return value.prototype.__gtype__
29
+
30
+ // An instance (or prototype).
31
+ if (value.__gtype__ !== undefined)
32
+ return value.__gtype__
33
+ }
34
+
35
+ throw new TypeError('getGType: expected a GObject/boxed class, instance, or GType')
36
+ }
37
+
14
38
  /*
15
39
  * Exports
16
40
  */
@@ -20,6 +44,7 @@ module.exports = {
20
44
  ...module_,
21
45
  startLoop: loop.start,
22
46
  registerClass: registerClass,
47
+ getGType: getGType,
23
48
  System: internal.System,
24
49
 
25
50
  // Private API
@@ -112,7 +112,8 @@ exports.apply = (Gtk) => {
112
112
  */
113
113
  Gtk.FileChooserDialog.prototype.getFile = function getFile() {
114
114
  const file = originalGetFile.call(this)
115
- file.__proto__= Gio.File.prototype
115
+ if (file)
116
+ file.__proto__= Gio.File.prototype
116
117
  return file
117
118
  }
118
119
 
@@ -122,7 +123,8 @@ exports.apply = (Gtk) => {
122
123
  */
123
124
  Gtk.FileChooserWidget.prototype.getFile = function getFile() {
124
125
  const file = originalGetFile.call(this)
125
- file.__proto__= Gio.File.prototype
126
+ if (file)
127
+ file.__proto__= Gio.File.prototype
126
128
  return file
127
129
  }
128
130
  }
@@ -119,7 +119,7 @@ function findVFuncOnParents(info, name) {
119
119
  function findVFuncOnInterfaces(gtype, name) {
120
120
  const interfaces = GObject.typeInterfaces(gtype);
121
121
 
122
- for (i = 0; i < interfaces.length; i++) {
122
+ for (let i = 0; i < interfaces.length; i++) {
123
123
  const interfaceInfo = findInfoByGtype(interfaces[i])
124
124
 
125
125
  /* The interface doesn't have to exist, it could be private
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "node-gtk",
3
- "version": "0.14.0",
3
+ "version": "2.0.0",
4
4
  "description": "GNOME Gtk+ bindings for NodeJS",
5
5
  "main": "lib/index.js",
6
+ "bin": {
7
+ "node-gtk": "bin/node-gtk.js"
8
+ },
6
9
  "scripts": {
7
10
  "install": "npx node-pre-gyp install --fallback-to-build",
11
+ "build:test-fixtures": "node scripts/build-test-fixtures.js",
12
+ "pretest": "node scripts/build-test-fixtures.js",
8
13
  "test": "mocha tests/__run__.js",
9
14
  "build": "npx node-pre-gyp build",
10
15
  "build:full": "npx node-pre-gyp rebuild",
@@ -36,8 +41,8 @@
36
41
  "lodash.camelcase": "4.3.0",
37
42
  "lodash.isequal": "4.5.0",
38
43
  "lodash.snakecase": "^4.1.1",
39
- "nan": "^2.17.0",
40
- "node-gyp": "^9.3.1",
44
+ "nan": "^2.27.0",
45
+ "node-gyp": "^11.2.0",
41
46
  "remove-trailing-spaces": "^1.0.7",
42
47
  "unindent": "^2.0.0"
43
48
  },
@@ -45,15 +50,17 @@
45
50
  "assert": "^1.5.0",
46
51
  "aws-sdk": "^2.452.0",
47
52
  "chalk": "^2.4.2",
48
- "deasync": "^0.1.19",
53
+ "deasync": "^0.1.30",
49
54
  "mocha": "^7.1.0",
50
55
  "nid-parser": "0.0.5",
51
- "node-pre-gyp-github": "^1.4.3"
56
+ "node-pre-gyp-github": "^1.4.5"
52
57
  },
53
58
  "files": [
59
+ "/bin",
54
60
  "/lib",
55
61
  "/src",
56
62
  "/scripts",
63
+ "/tools",
57
64
  "binding.gyp"
58
65
  ],
59
66
  "binary": {