ntk 2.2.0 → 3.1.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.
Files changed (47) hide show
  1. package/README.md +156 -151
  2. package/lib/app.js +64 -21
  3. package/lib/cleanup.js +14 -0
  4. package/lib/drawable.js +12 -18
  5. package/lib/events_map.js +92 -98
  6. package/lib/fontconfig.js +123 -17
  7. package/lib/glyphset.js +40 -21
  8. package/lib/image.js +138 -0
  9. package/lib/index.js +129 -57
  10. package/lib/path.js +734 -0
  11. package/lib/picture.js +84 -41
  12. package/lib/pixmap.js +50 -39
  13. package/lib/rasterize.js +178 -0
  14. package/lib/renderingcontext_2d.js +1078 -695
  15. package/lib/renderingcontext_opengl.js +53 -46
  16. package/lib/renderingcontext_x11.js +59 -67
  17. package/lib/text/font.js +196 -0
  18. package/lib/text/fontmanager.js +233 -0
  19. package/lib/text/fontsource.js +179 -0
  20. package/lib/text/glyphs.js +456 -0
  21. package/lib/text/layout.js +356 -0
  22. package/lib/text/shape.js +141 -0
  23. package/lib/trapezoid.js +131 -0
  24. package/lib/widgets/css.js +676 -0
  25. package/lib/widgets/highlight.js +97 -0
  26. package/lib/widgets/htmlview.js +879 -0
  27. package/lib/widgets/markdown.js +148 -0
  28. package/lib/widgets/markdownview.js +487 -0
  29. package/lib/widgets/mermaid.js +720 -0
  30. package/lib/widgets/svgview.js +528 -0
  31. package/lib/widgets/tex.js +681 -0
  32. package/lib/window.js +691 -308
  33. package/package.json +60 -56
  34. package/examples/example-await.js +0 -23
  35. package/examples/example-co.js +0 -13
  36. package/examples/example.js +0 -14
  37. package/examples/fill-styles.js +0 -39
  38. package/examples/glclock.js +0 -100
  39. package/examples/glxpixmap.js +0 -12
  40. package/examples/gradient.js +0 -41
  41. package/examples/package.json +0 -17
  42. package/examples/simpletex.js +0 -72
  43. package/examples/teapot.js +0 -104
  44. package/examples/teapot.json +0 -6
  45. package/examples/text-rendering.js +0 -44
  46. package/lib/fontface.js +0 -103
  47. package/lib/widgets/webview.js +0 -33
package/README.md CHANGED
@@ -1,151 +1,156 @@
1
- ntk
2
- ===
3
-
4
- node.js desktop UI toolkit
5
-
6
- A set of wrappers around low level [node-x11](https://github.com/sidorares/node-x11) module to simplify X Window UI progamming - windows creation, event handling, 2d/3d graphics etc.
7
-
8
- # Installation
9
-
10
- ```
11
- npm install ntk
12
- ```
13
-
14
- ## Basic usage
15
-
16
- ```js
17
- require('ntk').createClient( (err, app) => {
18
- var mainWnd = app.createWindow({ width: 500, height: 300, title: 'Hello' });
19
- mainWnd.on('mousedown', (ev) => { mainWnd.setTitle('click: ' + [ev.x, ev.y].join(',')); });
20
- mainWnd.map();
21
- });
22
- ```
23
-
24
- ## 2d graphics
25
-
26
- Each window ( or pixmap ) can be used to create 2d and 3d canvas. 2d canvas implements HTML [context2d api](https://html.spec.whatwg.org/multipage/scripting.html#2dcontext) ( some features not yet supported ) via [XRender extension](http://www.x.org/releases/X11R7.7/doc/renderproto/renderproto.txt), and most operations are performed on the X Server side ( image composition, scaling, blur, text composition, gradients etc ). Initial font rendering is performed by ntk using [freetype2](https://github.com/ericfreese/node-freetype2) module and fonts names mapped to file names using [font-manager](https://github.com/devongovett/font-manager) module.
27
-
28
- ```js
29
- var ntk = require('ntk');
30
-
31
- ntk.createClient( (err, app) => {
32
- var wnd = app.createWindow({ width: 800, height: 600});
33
- var ctx = wnd.getContext('2d');
34
-
35
- wnd.on('mousemove', (ev) => {
36
- var gradient = ctx.createRadialGradient(0, 0, 10, ev.x, ev.y, 500);
37
- gradient.addColorStop(0, "red");
38
- gradient.addColorStop(0.5, "green");
39
- gradient.addColorStop(1, "rgba(255, 255, 255, 0)");
40
- ctx.fillStyle = gradient;
41
- ctx.fillRect(0, 0, ctx.width, ctx.height);
42
- });
43
-
44
- wnd.map();
45
- });
46
- ```
47
-
48
- `ctx.drawImage()` also accepts [node-canvas](https://github.com/Automattic/node-canvas) as a source, for images with lot's of drawing calls it might be more efficient to perform all drawing locally and transfer pixels to server when ready:
49
-
50
- ```js
51
- var ntk = require('ntk');
52
- var Canvas = require('canvas');
53
-
54
- var canvas = new Canvas(800, 800);
55
- var canvasCtx = canvas.getContext('2d');
56
-
57
- function drawSomething(ctx) {
58
- // ...
59
- }
60
-
61
- ntk.createClient( (err, app) => {
62
- var wnd = app.createWindow({ width: 800, height: 800});
63
-
64
- var ctx = wnd.getContext('2d');
65
-
66
- setInterval(function() {
67
- drawSomething(canvasCtx);
68
- ctx.drawImage(canvas);
69
- }, 20);
70
-
71
- wnd.map();
72
- });
73
- ```
74
-
75
- ## 3d graphics
76
-
77
- At the moment only indirect GLX is supported with most of OpenGL 1.4 api implemented. Note that on some systems indirect GLX might be disabled by default, [you'll need to enable it for gl to work](https://github.com/sidorares/node-x11/issues/117#issuecomment-214762185).
78
-
79
- ```js
80
- var ntk = require('ntk');
81
-
82
- var width = 300;
83
- var height = 300;
84
- var angle = 0;
85
-
86
- function resize(gl) {
87
- gl.Viewport(0, 0, width, height);
88
- gl.MatrixMode(gl.PROJECTION);
89
- gl.LoadIdentity();
90
- if (width < height)
91
- gl.Frustum(-1.0, 1.0, -height/width, height/width, -35.0, 20);
92
- else
93
- gl.Frustum(-width/height, width/height, -1.0, 1.0, -35.0, 20);
94
- }
95
-
96
- function draw(gl) {
97
- gl.MatrixMode(gl.MODELVIEW);
98
-
99
- gl.ClearColor(0.3,0.3,0.3,0.0);
100
- gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
101
-
102
- gl.LoadIdentity();
103
- gl.Rotatef(-90 + 360*angle/width, 0, 0, 1);
104
- gl.Begin(gl.TRIANGLE_STRIP);
105
- gl.TexCoord2f(0.0,0.0);
106
- gl.Vertex3f(-1, -1, 0);
107
-
108
- gl.TexCoord2f(1.0, 0.0);
109
- gl.Vertex3f(1, -1, 0);
110
-
111
- gl.TexCoord2f(0.0, 1.0);
112
- gl.Vertex3f(-1, 1, 0);
113
-
114
- gl.TexCoord2f(1.0,1.0);
115
- gl.Vertex3f(1, 1, 0);
116
- gl.End();
117
- gl.SwapBuffers();
118
- }
119
-
120
- var texture = require('baboon-image');
121
-
122
- ntk.createClient(function(err, app) {
123
-
124
- var wnd = app.createWindow({width: width, height: height});
125
- wnd.map();
126
- var gl = wnd.getContext('opengl');
127
- gl.Enable(gl.TEXTURE_2D);
128
- gl.GenTextures(1, function(err, textures) {
129
- gl.BindTexture(gl.TEXTURE_2D, textures[0]);
130
- gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
131
- gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
132
- gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, 512, 512, 0, gl.RGB, gl.UNSIGNED_BYTE, texture.data);
133
- draw(gl);
134
-
135
- wnd.on('resize', function(ev) {
136
- width = ev.width;
137
- height = ev.height;
138
- resize(gl);
139
- draw(gl);
140
- }).on('mousemove', function(ev) {
141
- angle = ev.x;
142
- draw(gl);
143
- });
144
- });
145
- });
146
-
147
- ```
148
-
149
- ## High level widgets / layout management etc
150
-
151
- Likely to be implemented outside as part of [react-x11](https://github.com/sidorares/react-x11)
1
+ ntk
2
+ ===
3
+
4
+ node.js desktop UI toolkit for X11
5
+
6
+ A set of wrappers around the low level [node-x11](https://github.com/sidorares/node-x11)
7
+ module to simplify X Window UI programming — window creation, DOM-style event
8
+ handling, 2d/3d graphics — using API concepts you already know from the web.
9
+
10
+ Everything, including font rasterization, is pure JavaScript: `npm install`
11
+ never compiles anything.
12
+
13
+ **Docs & live playground:** <https://sidorares.github.io/ntk/> — the
14
+ playground runs ordinary ntk code in your browser against node-x11's
15
+ in-browser pure-JS X server (XRender included) with bundled fonts. The same server also works headless in node — see
16
+ [docs/xserver.md](docs/xserver.md) — so ntk apps and tests can run with no
17
+ real X server at all.
18
+
19
+ # Installation
20
+
21
+ ```
22
+ npm install ntk
23
+ ```
24
+
25
+ Requires Node.js >= 20.19 and an X server. Full documentation lives in
26
+ [docs/](docs/README.md).
27
+
28
+ ## Basic usage
29
+
30
+ ```js
31
+ import { createClient } from 'ntk';
32
+
33
+ const app = await createClient();
34
+ const wnd = app.createWindow({ width: 500, height: 300, title: 'Hello' });
35
+ wnd.on('mousedown', (ev) => wnd.setTitle(`click: ${ev.x},${ev.y}`));
36
+ wnd.map();
37
+ ```
38
+
39
+ ## 2d graphics
40
+
41
+ Each window (or pixmap) can create a 2d canvas implementing the HTML
42
+ [context2d api](https://html.spec.whatwg.org/multipage/canvas.html#2dcontext)
43
+ via the
44
+ [XRender extension](https://www.x.org/releases/X11R7.7/doc/renderproto/renderproto.txt) —
45
+ paths (arcs, beziers, `Path2D` with SVG path data, non-zero/even-odd fill
46
+ rules), transforms with `save()`/`restore()`, clipping, `globalAlpha` and
47
+ Porter-Duff composite ops ([docs/context-2d.md](docs/context-2d.md)).
48
+ Most operations are performed on the X server side (image composition,
49
+ scaling, blur, text composition, gradients etc). Text is fully shaped in
50
+ pure JS — OpenType kerning/ligatures and complex scripts (fontkit), bidi
51
+ (bidi-js), automatic font fallback — rasterized by a built-in scanline
52
+ rasterizer and cached server-side as XRender glyphs, so drawing a line of
53
+ text costs about a byte per glyph on the wire. Font names resolve through
54
+ fontconfig (`fc-match`). Very large and continuously animated sizes render
55
+ as server-side trapezoids instead of cached bitmaps. A `TextLayout` engine
56
+ wraps styled text to a target width, a `MarkdownView` widget renders
57
+ markdown (with syntax-highlighted code fences, mermaid flowchart/sequence
58
+ diagrams, and KaTeX math via `TexView`) on top of it — see
59
+ [docs/text.md](docs/text.md), [docs/mermaid.md](docs/mermaid.md) and
60
+ [docs/tex.md](docs/tex.md).
61
+
62
+ PNG/JPEG images decode client-side (`loadImage`) and composite server-side
63
+ via `ctx.drawImage` ([docs/images.md](docs/images.md)). An `HtmlView`
64
+ widget renders a static HTML + CSS subset — block flow and flexbox laid
65
+ out by yoga-layout, no scripts, no network — with app-controlled link
66
+ navigation ([docs/html.md](docs/html.md)). An `SvgView` widget renders
67
+ static SVG (shapes, gradients, transforms, `use`) through the same 2d
68
+ pipeline ([docs/svg.md](docs/svg.md)).
69
+
70
+ ```js
71
+ import { createClient } from 'ntk';
72
+
73
+ const app = await createClient();
74
+ const wnd = app.createWindow({ width: 800, height: 600 });
75
+ const ctx = wnd.getContext('2d');
76
+
77
+ wnd.on('mousemove', (ev) => {
78
+ const gradient = ctx.createRadialGradient(0, 0, 10, ev.x, ev.y, 500);
79
+ gradient.addColorStop(0, 'red');
80
+ gradient.addColorStop(0.5, 'green');
81
+ gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
82
+ ctx.fillStyle = gradient;
83
+ ctx.fillRect(0, 0, ctx.width, ctx.height);
84
+ });
85
+
86
+ wnd.map();
87
+ ```
88
+
89
+ `ctx.drawImage()` also accepts a [node-canvas](https://github.com/Automattic/node-canvas)
90
+ canvas as a source — for images with lots of drawing calls it might be more
91
+ efficient to draw locally and transfer pixels to the server when ready.
92
+
93
+ ## Frame pacing & networked displays
94
+
95
+ Noisy events (`resize`, `mousemove`, `expose`) are coalesced into paced
96
+ frames — the latest state wins, nothing queues up — and each frame is
97
+ fenced with a server round-trip, so rendering automatically slows to the
98
+ connection's real throughput instead of drawing a trail of stale updates
99
+ over ssh-forwarded displays. Animation uses the DOM-style
100
+ `requestAnimationFrame`:
101
+
102
+ ```js
103
+ function frame(now) {
104
+ // ... draw ...
105
+ wnd.requestAnimationFrame(frame); // ~60fps locally, RTT-paced remotely
106
+ }
107
+ wnd.requestAnimationFrame(frame);
108
+ ```
109
+
110
+ See [docs/window.md](docs/window.md) for the knobs (`frameInterval`,
111
+ `frameSync`, `coalesceEvents`) and the raw uncoalesced event stream.
112
+
113
+ ## Resource management
114
+
115
+ Server-side resources support `using` / `await using` (Node 24+):
116
+
117
+ ```js
118
+ {
119
+ await using app = await createClient();
120
+ using pixmap = app.createPixmap({ width: 256, height: 256, depth: 24 });
121
+ // ... draw ...
122
+ } // pixmap freed, connection closed
123
+ ```
124
+
125
+ ## 3d graphics
126
+
127
+ Only indirect GLX is supported, with most of the OpenGL 1.4 api implemented.
128
+ Note that on many systems indirect GLX is disabled by default —
129
+ [you'll need to enable it for gl to work](https://github.com/sidorares/node-x11/issues/117#issuecomment-214762185).
130
+
131
+ ```js
132
+ import { createClient } from 'ntk';
133
+
134
+ const app = await createClient();
135
+ const wnd = app.createWindow({ width: 300, height: 300 });
136
+ wnd.map();
137
+
138
+ const gl = wnd.getContext('opengl');
139
+ gl.ClearColor(0.3, 0.3, 0.3, 0.0);
140
+ gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
141
+ gl.Begin(gl.TRIANGLES);
142
+ gl.Color3f(1, 0, 0);
143
+ gl.Vertex3f(-1, -1, 0);
144
+ gl.Vertex3f(1, -1, 0);
145
+ gl.Vertex3f(0, 1, 0);
146
+ gl.End();
147
+ gl.SwapBuffers();
148
+ ```
149
+
150
+ See [examples/](examples/) for more (teapot, GL clock, textures, text
151
+ rendering).
152
+
153
+ ## High level widgets / layout management etc
154
+
155
+ Likely to be implemented outside as part of a react renderer
156
+ ([react-x11](https://github.com/sidorares/react-x11)).
package/lib/app.js CHANGED
@@ -1,21 +1,64 @@
1
- var Window = require('./window');
2
- var Pixmap = require('./pixmap');
3
-
4
- module.exports = App;
5
-
6
- function App(display) {
7
- this.display = display;
8
- this.X = display.client;
9
- }
10
-
11
- App.prototype.createWindow = function(args) {
12
- return new Window(this, args);
13
- }
14
-
15
- App.prototype.rootWindow = function() {
16
- return new Window(this, { id: this.display.screen[0].root} );
17
- }
18
-
19
- App.prototype.createPixmap = function(args) {
20
- return new Pixmap(this, args);
21
- }
1
+ import Pixmap from './pixmap.js';
2
+ import FontManager from './text/fontmanager.js';
3
+ import Window from './window.js';
4
+
5
+ /**
6
+ * A connection to an X server. Owns the underlying node-x11 client
7
+ * (`app.X`) and acts as a factory for windows and pixmaps.
8
+ */
9
+ export default class App {
10
+ /**
11
+ * @param {object} display node-x11 display
12
+ * @param {object} [options] environment hooks: { fontSource (see
13
+ * text/fontsource.js), glxVisual (visual id for getContext('opengl')
14
+ * when glxinfo can't be shelled out to) }
15
+ */
16
+ constructor(display, options = {}) {
17
+ this.display = display;
18
+ this.X = display.client;
19
+ this.options = options;
20
+ this._fonts = null;
21
+ // node-x11 emits X errors it cannot route to a request callback as
22
+ // 'error' on the client — from inside its packet parser. With no
23
+ // listener that emit throws and the parser never re-arms, silently
24
+ // wedging the connection (every later reply is dropped). Benign races
25
+ // (e.g. a request landing after its window was destroyed) become a
26
+ // warning instead; pass { onXError } to handle them yourself.
27
+ this.X.on('error', (err) => {
28
+ if (this.options.onXError) this.options.onXError(err);
29
+ else console.warn(`ntk: unhandled X error: ${err.message} (opcode ${err.majorOpcode}, seq ${err.seq})`);
30
+ });
31
+ }
32
+
33
+ /** the text API entry point: font matching/loading, shaping, layout */
34
+ get fonts() {
35
+ if (!this._fonts) this._fonts = new FontManager({ source: this.options.fontSource });
36
+ return this._fonts;
37
+ }
38
+
39
+ createWindow(args) {
40
+ return new Window(this, args);
41
+ }
42
+
43
+ rootWindow() {
44
+ return new Window(this, { id: this.display.screen[0].root });
45
+ }
46
+
47
+ createPixmap(args) {
48
+ return new Pixmap(this, args);
49
+ }
50
+
51
+ // flush pending requests and close the connection
52
+ close() {
53
+ return new Promise((resolve) => this.X.close(resolve));
54
+ }
55
+
56
+ async [Symbol.asyncDispose]() {
57
+ await this.close();
58
+ }
59
+
60
+ // sync variant: terminates without waiting for a flush round-trip
61
+ [Symbol.dispose]() {
62
+ this.X.terminate();
63
+ }
64
+ }
package/lib/cleanup.js ADDED
@@ -0,0 +1,14 @@
1
+ // Release a server-side resource, tolerating a connection that is closing or
2
+ // already gone — the X server frees all of a client's resources on disconnect,
3
+ // so there is nothing left to do and nothing worth throwing about. This
4
+ // matters for FinalizationRegistry callbacks, which run after app.close() if
5
+ // wrappers get garbage collected late and have no user code around them to
6
+ // catch.
7
+ export function safeRelease(X, fn) {
8
+ if (X._closing || !X.stream || X.stream.destroyed || X.stream.writableEnded) return;
9
+ try {
10
+ fn();
11
+ } catch {
12
+ // connection raced shut between the check and the request
13
+ }
14
+ }
package/lib/drawable.js CHANGED
@@ -1,18 +1,12 @@
1
- var EventEmitter = require('events').EventEmitter;
2
- var util = require('util');
3
-
4
- module.exports = Drawable;
5
-
6
- function Drawable() {
7
- EventEmitter.call(this);
8
- }
9
- util.inherits(Drawable, EventEmitter);
10
-
11
- Drawable.prototype.renderingContextFactory = {};
12
-
13
- Drawable.prototype.getContext = function(name, arg1, arg2, arg3) {
14
- var renderingContextFactory = this.renderingContextFactory[name];
15
- if (!renderingContextFactory)
16
- throw new Error('Unknown rendering context:', name);
17
- return renderingContextFactory(this, arg1, arg2, arg3);
18
- }
1
+ import { EventEmitter } from 'node:events';
2
+
3
+ export default class Drawable extends EventEmitter {
4
+ getContext(name, ...args) {
5
+ const factory = Drawable.renderingContextFactory[name];
6
+ if (!factory) throw new Error(`Unknown rendering context: ${name}`);
7
+ return factory(this, ...args);
8
+ }
9
+ }
10
+
11
+ // populated by the renderingcontext_* modules on import
12
+ Drawable.renderingContextFactory = {};
package/lib/events_map.js CHANGED
@@ -1,98 +1,92 @@
1
- var x11 = require('x11');
2
-
3
- // todo: move event names to node-x11, it should be part of event object
4
- var eventIdToName = module.exports.eventName = [];
5
- eventIdToName[2] = 'keydown';
6
- eventIdToName[3] = 'keyup';
7
- eventIdToName[4] = 'mousedown';
8
- eventIdToName[5] = 'mouseup';
9
- eventIdToName[6] = 'mousemove';
10
- eventIdToName[7] = 'mouseover';
11
- eventIdToName[8] = 'mouseout';
12
- eventIdToName[12] = 'expose';
13
- eventIdToName[17] = 'destroy';
14
- eventIdToName[18] = 'unmap';
15
- eventIdToName[19] = 'map';
16
- eventIdToName[20] = 'map_request';
17
- eventIdToName[21] = 'reparent';
18
- eventIdToName[22] = 'resize';
19
- eventIdToName[23] = 'configure_request';
20
- // 25 - gravity
21
- eventIdToName[25] = 'resize_request';
22
- eventIdToName[26] = 'circulate';
23
- eventIdToName[27] = 'circulate_request';
24
- eventIdToName[28] = 'property';
25
- eventIdToName[29] = 'selection_clear';
26
- eventIdToName[30] = 'selection_request';
27
- eventIdToName[31] = 'selection';
28
- eventIdToName[33] = 'message';
29
-
30
- // event mask you need to select to receive event
31
- // 0 = no need to express interest, event is sent regardless of mask
32
- module.exports.mask = {
33
- 'mousemove': x11.eventMask.PointerMotion,
34
- 'mouseover': x11.eventMask.EnterWindow,
35
- 'mouseout': x11.eventMask.LeaveWindow,
36
- 'mousedown': x11.eventMask.ButtonPress,
37
- 'mouseup': x11.eventMask.ButtonRelease,
38
- 'map' : x11.eventMask.StructureNotify,
39
- 'unmap': x11.eventMask.StructureNotify,
40
- 'resize': x11.eventMask.StructureNotify,
41
- 'reparent': x11.eventMask.StructureNotify,
42
- 'keydown': x11.eventMask.KeyPress,
43
- 'expose': x11.eventMask.Exposure,
44
- 'map_request': x11.eventMask.SubstructureRedirect,
45
- 'configure_request': x11.eventMask.SubstructureRedirect,
46
- 'destroy': x11.eventMask.StructureNotify,
47
- 'keyup': x11.eventMask.KeyRelease,
48
- 'property': x11.eventMask.PropertyChange,
49
- 'selection': 0,
50
- 'selection_request': 0,
51
- 'message': 0
52
- };
53
-
54
- module.exports.maskCamelCase = {
55
- 'onMouseMove': x11.eventMask.PointerMotion,
56
- 'onMouseOver': x11.eventMask.EnterWindow,
57
- 'onMouseOut': x11.eventMask.LeaveWindow,
58
- 'onMouseDown': x11.eventMask.ButtonPress,
59
- 'onMouseUp': x11.eventMask.ButtonRelease,
60
- 'onMap' : x11.eventMask.StructureNotify,
61
- 'onUnmap': x11.eventMask.StructureNotify,
62
- 'onResize': x11.eventMask.StructureNotify,
63
- 'onReparent': x11.eventMask.StructureNotify,
64
- 'onKeyDown': x11.eventMask.KeyPress,
65
- 'onExpose': x11.eventMask.Exposure,
66
- 'onMapRequest': x11.eventMask.SubstructureRedirect,
67
- 'onConfigureRequest': x11.eventMask.SubstructureRedirect,
68
- 'onDestroy': x11.eventMask.StructureNotify,
69
- 'onKeyUp': x11.eventMask.KeyRelease,
70
- 'onPropertyChange': x11.eventMask.PropertyChange,
71
- // TODO
72
- 'onSelection': 0,
73
- 'onSelectionRequest': 0,
74
- 'onMessage': 0
75
- };
76
-
77
- module.exports.toSnake = {
78
- 'onMouseMove': 'mousemove',
79
- 'onMouseOver': 'mouseover',
80
- 'onMouseOut': 'mouseout',
81
- 'onMouseDown': 'mousedown',
82
- 'onMouseUp': 'mouseup',
83
- 'onMap' : 'map',
84
- 'onUnmap': 'unmap',
85
- 'onResize': 'resize',
86
- 'onReparent': 'reparent',
87
- 'onKeyDown': 'keydown',
88
- 'onExpose': 'expose',
89
- 'onMapRequest': 'map_request',
90
- 'onConfigureRequest': 'configure_request',
91
- 'onDestroy': 'destroy',
92
- 'onKeyUp': 'keyup',
93
- 'onPropertyChange': 'property',
94
- // TODO
95
- 'onSelection': 'selection',
96
- 'onSelectionRequest': 'selection_request',
97
- 'onMessage': 'message'
98
- };
1
+ import x11 from 'x11';
2
+
3
+ // todo: move event names to node-x11, it should be part of event object
4
+ export const eventName = [];
5
+ eventName[2] = 'keydown';
6
+ eventName[3] = 'keyup';
7
+ eventName[4] = 'mousedown';
8
+ eventName[5] = 'mouseup';
9
+ eventName[6] = 'mousemove';
10
+ eventName[7] = 'mouseover';
11
+ eventName[8] = 'mouseout';
12
+ eventName[12] = 'expose';
13
+ eventName[17] = 'destroy';
14
+ eventName[18] = 'unmap';
15
+ eventName[19] = 'map';
16
+ eventName[20] = 'map_request';
17
+ eventName[21] = 'reparent';
18
+ eventName[22] = 'resize';
19
+ eventName[23] = 'configure_request';
20
+ // 25 - gravity
21
+ eventName[25] = 'resize_request';
22
+ eventName[26] = 'circulate';
23
+ eventName[27] = 'circulate_request';
24
+ eventName[28] = 'property';
25
+ eventName[29] = 'selection_clear';
26
+ eventName[30] = 'selection_request';
27
+ eventName[31] = 'selection';
28
+ eventName[33] = 'message';
29
+
30
+ // event mask you need to select to receive event
31
+ // 0 = no need to express interest, event is sent regardless of mask
32
+ export const mask = {
33
+ mousemove: x11.eventMask.PointerMotion,
34
+ mouseover: x11.eventMask.EnterWindow,
35
+ mouseout: x11.eventMask.LeaveWindow,
36
+ mousedown: x11.eventMask.ButtonPress,
37
+ mouseup: x11.eventMask.ButtonRelease,
38
+ map: x11.eventMask.StructureNotify,
39
+ unmap: x11.eventMask.StructureNotify,
40
+ resize: x11.eventMask.StructureNotify,
41
+ reparent: x11.eventMask.StructureNotify,
42
+ keydown: x11.eventMask.KeyPress,
43
+ expose: x11.eventMask.Exposure,
44
+ map_request: x11.eventMask.SubstructureRedirect,
45
+ configure_request: x11.eventMask.SubstructureRedirect,
46
+ destroy: x11.eventMask.StructureNotify,
47
+ keyup: x11.eventMask.KeyRelease,
48
+ property: x11.eventMask.PropertyChange,
49
+ selection: 0,
50
+ selection_request: 0,
51
+ message: 0
52
+ };
53
+
54
+ // events that are noisy by nature: intermediate occurrences carry no
55
+ // information the final one doesn't, so Window merges bursts into a single
56
+ // event per paced frame (see docs/window.md). 'last' — the newest event
57
+ // wins (older ones ride along in ev.coalesced); 'union' — damage
58
+ // rectangles accumulate (bounding box in ev.x/y/width/height, every rect
59
+ // in ev.rects).
60
+ export const coalesce = {
61
+ mousemove: 'last',
62
+ resize: 'last',
63
+ expose: 'union'
64
+ };
65
+
66
+ export const toSnake = {
67
+ onMouseMove: 'mousemove',
68
+ onMouseOver: 'mouseover',
69
+ onMouseOut: 'mouseout',
70
+ onMouseDown: 'mousedown',
71
+ onMouseUp: 'mouseup',
72
+ onMap: 'map',
73
+ onUnmap: 'unmap',
74
+ onResize: 'resize',
75
+ onReparent: 'reparent',
76
+ onKeyDown: 'keydown',
77
+ onExpose: 'expose',
78
+ onMapRequest: 'map_request',
79
+ onConfigureRequest: 'configure_request',
80
+ onDestroy: 'destroy',
81
+ onKeyUp: 'keyup',
82
+ onPropertyChange: 'property',
83
+ onSelection: 'selection',
84
+ onSelectionRequest: 'selection_request',
85
+ onMessage: 'message'
86
+ };
87
+
88
+ export const maskCamelCase = Object.fromEntries(
89
+ Object.entries(toSnake).map(([camel, snake]) => [camel, mask[snake]])
90
+ );
91
+
92
+ export default { eventName, mask, maskCamelCase, toSnake, coalesce };