ntk 3.0.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.
- package/lib/app.js +10 -0
- package/lib/index.js +8 -2
- package/lib/window.js +59 -10
- package/package.json +1 -1
package/lib/app.js
CHANGED
|
@@ -18,6 +18,16 @@ export default class App {
|
|
|
18
18
|
this.X = display.client;
|
|
19
19
|
this.options = options;
|
|
20
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
|
+
});
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
/** the text API entry point: font matching/loading, shaping, layout */
|
package/lib/index.js
CHANGED
|
@@ -38,8 +38,10 @@ import './renderingcontext_opengl.js';
|
|
|
38
38
|
* @param {object} [options] passed through to x11.createClient
|
|
39
39
|
* (e.g. { display: ':1' }); ntk additionally understands
|
|
40
40
|
* { fontSource } — a pluggable system-font lookup (see docs/fonts.md) —
|
|
41
|
-
*
|
|
42
|
-
* environments where `glxinfo` cannot be shelled out to
|
|
41
|
+
* { glxVisual } — the visual id for getContext('opengl') in
|
|
42
|
+
* environments where `glxinfo` cannot be shelled out to — and
|
|
43
|
+
* { onXError } — called with X protocol errors no request callback
|
|
44
|
+
* claimed (default: console.warn)
|
|
43
45
|
* @param {function} [callback] optional node-style callback
|
|
44
46
|
* @returns {Promise<App>}
|
|
45
47
|
*/
|
|
@@ -120,4 +122,8 @@ export {
|
|
|
120
122
|
configureTex,
|
|
121
123
|
highlightCode
|
|
122
124
|
};
|
|
125
|
+
// the yoga-layout instance ntk lays HtmlView out with — downstream layout
|
|
126
|
+
// consumers (e.g. the react-x11 renderer) must share it to avoid loading a
|
|
127
|
+
// second WASM copy with potentially mismatched enums
|
|
128
|
+
export { default as Yoga } from 'yoga-layout';
|
|
123
129
|
export default { createClient };
|
package/lib/window.js
CHANGED
|
@@ -6,6 +6,31 @@ import Drawable from './drawable.js';
|
|
|
6
6
|
import Pixmap from './pixmap.js';
|
|
7
7
|
import * as xevents from './events_map.js';
|
|
8
8
|
|
|
9
|
+
// X window attributes forwarded verbatim from constructor args into the
|
|
10
|
+
// CreateWindow value list (node-x11 valueMask names, see x11
|
|
11
|
+
// lib/corereqs.js). Deliberately not forwarded:
|
|
12
|
+
// - eventMask: computed from the onXxx handler args (an explicit
|
|
13
|
+
// args.eventMask is OR-ed into the computed mask instead)
|
|
14
|
+
// - backingStore: ntk's `backingStore: false` creation option opts out of
|
|
15
|
+
// client-side double buffering (see docs/window.md) and predates this
|
|
16
|
+
// list — it is a different concept from the X backing-store attribute,
|
|
17
|
+
// which is therefore not forwarded to avoid a silent collision
|
|
18
|
+
const forwardedXAttributes = [
|
|
19
|
+
'backgroundPixmap',
|
|
20
|
+
'backgroundPixel',
|
|
21
|
+
'borderPixmap',
|
|
22
|
+
'borderPixel',
|
|
23
|
+
'bitGravity',
|
|
24
|
+
'winGravity',
|
|
25
|
+
'backingPlanes',
|
|
26
|
+
'backingPixel',
|
|
27
|
+
'overrideRedirect',
|
|
28
|
+
'saveUnder',
|
|
29
|
+
'doNotPropagateMask',
|
|
30
|
+
'colormap',
|
|
31
|
+
'cursor'
|
|
32
|
+
];
|
|
33
|
+
|
|
9
34
|
export default class Window extends Drawable {
|
|
10
35
|
// one wrapper per X window id and connection: constructing a Window for a
|
|
11
36
|
// known id returns the cached instance
|
|
@@ -25,6 +50,8 @@ export default class Window extends Drawable {
|
|
|
25
50
|
this.app = app;
|
|
26
51
|
this.display = app.display;
|
|
27
52
|
this._mapped = false;
|
|
53
|
+
this._destroyed = false;
|
|
54
|
+
this._titleSerial = 0;
|
|
28
55
|
this._readyPromiseResolve = null;
|
|
29
56
|
this._readyPromise = new Promise((resolve) => {
|
|
30
57
|
this._readyPromiseResolve = resolve;
|
|
@@ -68,17 +95,25 @@ export default class Window extends Drawable {
|
|
|
68
95
|
}
|
|
69
96
|
}
|
|
70
97
|
|
|
98
|
+
if (typeof args.eventMask === 'number') {
|
|
99
|
+
this.eventMask |= args.eventMask;
|
|
100
|
+
}
|
|
101
|
+
|
|
71
102
|
this.width = args.width ?? 800;
|
|
72
103
|
this.height = args.height ?? 800;
|
|
73
104
|
this.x = args.x ?? 0;
|
|
74
105
|
this.y = args.y ?? 0;
|
|
75
|
-
|
|
106
|
+
const values = {
|
|
76
107
|
// NorthWest bit gravity: keep the old content anchored during
|
|
77
108
|
// resize instead of discarding it (less flicker between the resize
|
|
78
109
|
// and our redraw)
|
|
79
110
|
bitGravity: 1,
|
|
80
111
|
eventMask: this.eventMask
|
|
81
|
-
}
|
|
112
|
+
};
|
|
113
|
+
for (const name of forwardedXAttributes) {
|
|
114
|
+
if (args[name] !== undefined) values[name] = args[name];
|
|
115
|
+
}
|
|
116
|
+
X.CreateWindow(this.id, parentId, this.x, this.y, this.width, this.height, 0, 0, 0, 0, values);
|
|
82
117
|
} else {
|
|
83
118
|
this.id = args.id;
|
|
84
119
|
this.eventMask = 0;
|
|
@@ -171,6 +206,7 @@ export default class Window extends Drawable {
|
|
|
171
206
|
this.on('map', () => (this._mapped = true));
|
|
172
207
|
this.on('unmap', () => (this._mapped = false));
|
|
173
208
|
this.on('destroy', () => {
|
|
209
|
+
this._destroyed = true;
|
|
174
210
|
this._forget();
|
|
175
211
|
this._teardownFrame();
|
|
176
212
|
// the server frees window-backed pictures with the window — let
|
|
@@ -537,14 +573,26 @@ export default class Window extends Drawable {
|
|
|
537
573
|
}
|
|
538
574
|
|
|
539
575
|
setTitle(title) {
|
|
540
|
-
this.X
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
576
|
+
const X = this.X;
|
|
577
|
+
const wid = this.id;
|
|
578
|
+
// legacy WM_NAME is latin-1 only (node-x11 encodes plain strings as
|
|
579
|
+
// latin1) — kept for old window managers
|
|
580
|
+
X.ChangeProperty(0, wid, X.atoms.WM_NAME, X.atoms.STRING, 8, title);
|
|
581
|
+
// modern WMs prefer the EWMH _NET_WM_NAME property, which is UTF-8;
|
|
582
|
+
// interned atoms are cached by node-x11, so this round-trips only once.
|
|
583
|
+
// The lookups are async: by the time they resolve the window may be
|
|
584
|
+
// destroyed (ChangeProperty would BadWindow) or retitled (an older
|
|
585
|
+
// write would clobber a newer one) — the serial/destroyed guards drop
|
|
586
|
+
// the stale write in both cases.
|
|
587
|
+
const serial = ++this._titleSerial;
|
|
588
|
+
X.InternAtom(false, '_NET_WM_NAME', (err, netWmName) => {
|
|
589
|
+
X.InternAtom(false, 'UTF8_STRING', (err2, utf8String) => {
|
|
590
|
+
if (err || err2 || this._destroyed || serial !== this._titleSerial) return;
|
|
591
|
+
safeRelease(X, () => {
|
|
592
|
+
X.ChangeProperty(0, wid, netWmName, utf8String, 8, Buffer.from(title, 'utf8'));
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
});
|
|
548
596
|
return this;
|
|
549
597
|
}
|
|
550
598
|
|
|
@@ -622,6 +670,7 @@ export default class Window extends Drawable {
|
|
|
622
670
|
}
|
|
623
671
|
|
|
624
672
|
destroy() {
|
|
673
|
+
this._destroyed = true;
|
|
625
674
|
this._forget();
|
|
626
675
|
this._teardownFrame();
|
|
627
676
|
this.emit('_destroyed');
|