react-x11 2.52.0 → 2.54.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 +10 -10
- package/docs/README.md +160 -314
- package/docs/accessibility.md +176 -229
- package/docs/appearance.md +77 -176
- package/docs/click-to-component.md +18 -51
- package/docs/clipboard.md +40 -59
- package/docs/components.md +518 -1036
- package/docs/dbus.md +61 -133
- package/docs/debugging.md +152 -245
- package/docs/desktop-calendar.md +51 -88
- package/docs/desktop.md +222 -347
- package/docs/devtools.md +50 -167
- package/docs/drag-and-drop.md +126 -204
- package/docs/ecosystem/animation.md +91 -125
- package/docs/ecosystem/data-fetching.md +38 -53
- package/docs/ecosystem/dev-tooling.md +159 -202
- package/docs/ecosystem/forms.md +61 -97
- package/docs/ecosystem/headless.md +64 -89
- package/docs/ecosystem/i18n.md +18 -21
- package/docs/ecosystem/icons.md +93 -126
- package/docs/ecosystem/layout.md +42 -52
- package/docs/ecosystem/routing.md +18 -29
- package/docs/ecosystem/state.md +71 -88
- package/docs/ecosystem/testing.md +131 -157
- package/docs/ecosystem/theming.md +119 -165
- package/docs/ecosystem.md +145 -179
- package/docs/elements.md +1096 -1774
- package/docs/embedding.md +83 -132
- package/docs/events.md +412 -695
- package/docs/extending.md +784 -1326
- package/docs/eyedropper.md +63 -122
- package/docs/filedialog.md +71 -107
- package/docs/frame.md +195 -339
- package/docs/gl.md +65 -62
- package/docs/globalmenu.md +63 -146
- package/docs/macos.md +531 -3234
- package/docs/notifications.md +33 -47
- package/docs/packaging.md +166 -309
- package/docs/permissions.md +9 -14
- package/docs/react-features.md +81 -106
- package/docs/remote.md +32 -76
- package/docs/scale.md +72 -186
- package/docs/styling.md +329 -547
- package/docs/system.md +200 -280
- package/docs/testing.md +63 -83
- package/docs/typescript.md +6 -48
- package/docs/uri-schemes.md +67 -107
- package/docs/wayland-backend.md +200 -459
- package/docs/windows-integrations.md +75 -131
- package/docs/windows.md +343 -1367
- package/package.json +3 -2
- package/src/Reconciler.js +2 -2
- package/src/a11y.js +1 -1
- package/src/backend/context2d.js +3 -3
- package/src/bootstrap.js +1 -1
- package/src/cocoa/app.js +6 -6
- package/src/cocoa/bezels.js +1 -1
- package/src/cocoa/fonts.js +1 -1
- package/src/cocoa/globalmenu.js +1 -1
- package/src/cocoa/keymap.js +1 -1
- package/src/cocoa/panewindow.js +1 -1
- package/src/cocoa/player.js +1 -1
- package/src/cocoa/presenter.js +2 -2
- package/src/cocoa/promotion.js +1 -1
- package/src/cocoa/relaunch.js +1 -1
- package/src/cocoa/threaded.js +1 -1
- package/src/cocoa/video.js +1 -1
- package/src/cocoa/window.js +4 -4
- package/src/components/Menu.js +7 -2
- package/src/components/Switch.js +1 -1
- package/src/components/native.js +1 -1
- package/src/dnd.js +2 -2
- package/src/glnodes.js +1 -1
- package/src/grid.js +1 -1
- package/src/imagedecode-worker.js +32 -0
- package/src/imagedecode.js +140 -2
- package/src/layouts.js +1 -1
- package/src/nodes/animation.js +1 -1
- package/src/nodes/invalidate.js +1 -1
- package/src/nodes/layouthost.js +1 -1
- package/src/nodes/video.js +19 -8
- package/src/nodes/window/droptarget.js +1 -1
- package/src/ntk.d.ts +12 -0
- package/src/pacing.js +1 -1
- package/src/refresh/index.js +2 -1
- package/src/types/video.d.ts +5 -2
- package/src/videobackend.js +28 -0
- package/src/videoframes.js +29 -16
- package/src/wayland/app.js +27 -0
- package/src/wayland/video.js +376 -0
- package/src/win32/a11y.js +1 -1
- package/src/win32/app.js +2 -2
- package/src/win32/fonts.js +1 -1
- package/src/win32/glarea.js +4 -4
- package/src/win32/overlay.js +1 -1
- package/src/win32/panewindow.js +3 -3
- package/src/win32/shell.js +1 -1
- package/src/win32/window.js +2 -2
- package/src/windowid.js +1 -1
- package/src/xvideo.js +189 -0
- package/docs/architecture/accessibility.md +0 -470
- package/docs/architecture/animation.md +0 -707
- package/docs/architecture/container-queries.md +0 -525
- package/docs/architecture/custom-layout.md +0 -334
- package/docs/architecture/drag-and-drop.md +0 -941
- package/docs/architecture/element-layer-contents.md +0 -622
- package/docs/architecture/frame-pacing.md +0 -255
- package/docs/architecture/grid-layout.md +0 -358
- package/docs/architecture/protocol-efficiency.md +0 -357
- package/docs/architecture/video.md +0 -1149
- package/docs/architecture/windowed-regions.md +0 -854
- package/docs/glx.md +0 -137
- package/docs/wayland.md +0 -545
- package/docs/windows-embedding.md +0 -271
- package/docs/windows-gl.md +0 -221
package/src/win32/fonts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The Windows text engine: DirectWrite behind the same `app.fonts` contract
|
|
2
2
|
// ntk's FontManager answers on X11 and CoreText answers on macOS. The renderer
|
|
3
|
-
// touches exactly this surface (
|
|
3
|
+
// touches exactly this surface (design/windows.md §"Text"):
|
|
4
4
|
//
|
|
5
5
|
// fonts.layout(spans, base, { maxWidth, align, lineHeight, maxLines,
|
|
6
6
|
// overflow, direction })
|
package/src/win32/glarea.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// `<glarea>` on Windows: a WGL core context, composited as a visual.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
3
|
+
// design/windows-gl.md is the report behind this, and the route is the X11
|
|
4
4
|
// model rather than ANGLE — a GL surface covers its rect and the tree draws
|
|
5
5
|
// under it, positioned from the parent's yoga rect. src/glnodes.js already
|
|
6
6
|
// expects exactly that, including the rule that the surface selects no
|
|
@@ -58,7 +58,7 @@ export class Win32GlWindow {
|
|
|
58
58
|
* vendor driver: opengl32.dll is then the 1.1 software rasterizer, with no
|
|
59
59
|
* shaders and no framebuffer objects — which is not a degraded direct
|
|
60
60
|
* backend but the indirect one's feature set without its portability, and
|
|
61
|
-
* is
|
|
61
|
+
* is design/windows-gl.md's rung 2 rather than this one.
|
|
62
62
|
*/
|
|
63
63
|
_onReady(ok, why = 0) {
|
|
64
64
|
if (!ok) {
|
|
@@ -79,7 +79,7 @@ export class Win32GlWindow {
|
|
|
79
79
|
'error',
|
|
80
80
|
new Error(
|
|
81
81
|
`react-x11: no OpenGL surface — ${REASONS[why] ?? 'the bridge refused it'}. ` +
|
|
82
|
-
'
|
|
82
|
+
'design/windows-gl.md rung 2 (ANGLE) covers this case and is not built yet.',
|
|
83
83
|
),
|
|
84
84
|
);
|
|
85
85
|
return;
|
|
@@ -540,7 +540,7 @@ export function installGl(app) {
|
|
|
540
540
|
throw new Error(
|
|
541
541
|
'react-x11: <glarea> has no GL surface — this machine has no vendor ' +
|
|
542
542
|
'OpenGL driver, so only the 1.1 software rasterizer is available, ' +
|
|
543
|
-
'which has no shaders.
|
|
543
|
+
'which has no shaders. design/windows-gl.md rung 2 (ANGLE) covers ' +
|
|
544
544
|
'this case and is not built yet.',
|
|
545
545
|
);
|
|
546
546
|
});
|
package/src/win32/overlay.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// leave transparent shows the GL frame, and a translucent fill, an
|
|
14
14
|
// antialiased edge or a shadow blends with it. Text on it is grayscale
|
|
15
15
|
// rather than ClearType, which Direct2D does on any surface with alpha
|
|
16
|
-
// (
|
|
16
|
+
// (design/windows.md §Text).
|
|
17
17
|
//
|
|
18
18
|
// Drawn like the window it lives in (src/win32/window.js): a DirectComposition
|
|
19
19
|
// surface hands out a context per `BeginDraw`, valid until `EndDraw`, so the
|
package/src/win32/panewindow.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The pane process's "window" on the Windows backend —
|
|
1
|
+
// The pane process's "window" on the Windows backend — design/frame.md's child
|
|
2
2
|
// half, with the composition engine standing in for the X server.
|
|
3
3
|
//
|
|
4
4
|
// On X11 a pane renders into a real window of its own and the host reparents
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// the pane makes a DirectComposition surface handle, hangs a composition
|
|
7
7
|
// swapchain off it, and draws through the same verb table a window draws
|
|
8
8
|
// through; the host opens that handle and gives it to a visual of its own
|
|
9
|
-
// (src/win32/panehost.js). See
|
|
9
|
+
// (src/win32/panehost.js). See design/windows-embedding.md for why this rather
|
|
10
10
|
// than a shared DXGI texture — in one line, nothing here has to synchronise.
|
|
11
11
|
//
|
|
12
12
|
// **The present is the hand-off.** Once the host holds the handle the
|
|
@@ -360,7 +360,7 @@ export class Win32PaneWindow {
|
|
|
360
360
|
* On X11 that is the window's own id, because an XID means the same thing
|
|
361
361
|
* in every process on the display. Windows has no such number: a window
|
|
362
362
|
* cannot be embedded at all, because a composition target stops presenting
|
|
363
|
-
* the moment its window becomes a child (
|
|
363
|
+
* the moment its window becomes a child (design/windows-embedding.md, with
|
|
364
364
|
* the measurements). What crosses instead is the **buffer** — the same
|
|
365
365
|
* composition surface handle a `<Frame>` pane publishes — and the host
|
|
366
366
|
* binds it to a visual of its own rather than reparenting anything.
|
package/src/win32/shell.js
CHANGED
|
@@ -236,7 +236,7 @@ async function badgePixels(app, label, accent) {
|
|
|
236
236
|
* What this rung cannot do, and says so by not implementing it: actions,
|
|
237
237
|
* replacing a notification in place, and an icon of the app's own. Those want
|
|
238
238
|
* the Windows App SDK's notification manager and an AppUserModelID the system
|
|
239
|
-
* knows —
|
|
239
|
+
* knows — design/windows.md §"The desktop around the app". Until then the
|
|
240
240
|
* balloon is shown by the shell in the same place, with the same sound, and
|
|
241
241
|
* kept in the same action centre.
|
|
242
242
|
*/
|
package/src/win32/window.js
CHANGED
|
@@ -252,7 +252,7 @@ export class Win32Window {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
/** The size limits Windows asks for synchronously in WM_GETMINMAXINFO, so
|
|
255
|
-
* they are pushed ahead rather than answered on demand —
|
|
255
|
+
* they are pushed ahead rather than answered on demand — design/windows.md
|
|
256
256
|
* "What Windows asks synchronously, and JS can know in advance". */
|
|
257
257
|
setSizeHints(hints = {}) {
|
|
258
258
|
this._native.setSizeHints?.(this.id, hints);
|
|
@@ -691,7 +691,7 @@ export class Win32Window {
|
|
|
691
691
|
}
|
|
692
692
|
|
|
693
693
|
/** A DirectComposition surface is write-only, so a window's pixels are not
|
|
694
|
-
* readable the way an IOSurface's or an X drawable's are.
|
|
694
|
+
* readable the way an IOSurface's or an X drawable's are. design/windows.md
|
|
695
695
|
* answers this with PrintWindow once the commit has completed; not bound
|
|
696
696
|
* yet, and it says so rather than answering with something wrong. */
|
|
697
697
|
/**
|
package/src/windowid.js
CHANGED
|
@@ -78,7 +78,7 @@ export function windowOf(target) {
|
|
|
78
78
|
* - **Windows** — a **composition surface handle**, already valid in the
|
|
79
79
|
* host process. A window cannot be embedded here at all: a composition
|
|
80
80
|
* target stops presenting the moment its window becomes a child, measured
|
|
81
|
-
* in
|
|
81
|
+
* in design/windows-embedding.md. So what crosses is the buffer, and the
|
|
82
82
|
* host binds it to a visual of its own instead of reparenting. The host is
|
|
83
83
|
* the parent process by default — `createRoot({ win32: { paneHostPid } })`
|
|
84
84
|
* when it is not.
|
package/src/xvideo.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// `<video frames>` on X11 with the server doing the conversion: an XVideo
|
|
2
|
+
// port where the display has an image adaptor (ntk/xv;
|
|
3
|
+
// design/architecture/video.md §2.6).
|
|
4
|
+
//
|
|
5
|
+
// The drawn path converts each YCbCr frame in a JavaScript loop over every
|
|
6
|
+
// pixel and puts four bytes a pixel on the wire. Through Xv the frame
|
|
7
|
+
// crosses as the decoder made it — 1.5 bytes a pixel for NV12 and I420,
|
|
8
|
+
// through shared memory on a local display — and the matrix is the server's
|
|
9
|
+
// GPU's: glamor's textured adaptor, which Xorg's modesetting driver and
|
|
10
|
+
// Xwayland both ship.
|
|
11
|
+
//
|
|
12
|
+
// Where the frame goes is the record's open question, answered by
|
|
13
|
+
// measurement: an adaptor takes no pixmap (`BadWindow` into one on
|
|
14
|
+
// Xwayland), so the frame goes into a `VideoTarget` — a manually redirected
|
|
15
|
+
// child window outside the window it belongs to, shown nowhere — and from
|
|
16
|
+
// there, in one RENDER copy, into the `<video>`'s own surface. Everything
|
|
17
|
+
// after that is the drawn path unchanged: the surface is composited in paint
|
|
18
|
+
// order, under the window's popups and inside its scroll panes, and painted
|
|
19
|
+
// again from without a frame.
|
|
20
|
+
//
|
|
21
|
+
// Declined, and the frame goes the JavaScript way, where the server has no
|
|
22
|
+
// image adaptor (Xvfb, XQuartz, most remote displays), where ntk predates
|
|
23
|
+
// ntk/xv, for a full-range frame or a colour space the port cannot be told
|
|
24
|
+
// (every adaptor reads video range; one without XV_COLORSPACE reads BT.601
|
|
25
|
+
// alone), while the window is not on screen, and for the first frame of a
|
|
26
|
+
// size, while the port says how it wants it laid out.
|
|
27
|
+
//
|
|
28
|
+
// Nothing is asked of the server until a sink or a `<video>` asks: an app
|
|
29
|
+
// that shows no video grabs no port and pays no round trip.
|
|
30
|
+
|
|
31
|
+
const writers = new WeakMap();
|
|
32
|
+
|
|
33
|
+
/** The writer for `app`'s connection, made on first ask. */
|
|
34
|
+
export function xvVideoFor(app) {
|
|
35
|
+
let writer = writers.get(app);
|
|
36
|
+
if (!writer) writers.set(app, (writer = new XvVideo(app)));
|
|
37
|
+
return writer;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const same = (planes) => planes;
|
|
41
|
+
const swapChroma = (planes) => planes && [planes[0], planes[2], planes[1]];
|
|
42
|
+
|
|
43
|
+
/** A sink's format, as the formats a port may take it in — the planes put
|
|
44
|
+
* in the port's order — cheapest first. */
|
|
45
|
+
const PORT_FORMATS = {
|
|
46
|
+
NV12: [['NV12', same]],
|
|
47
|
+
I420: [
|
|
48
|
+
['I420', same],
|
|
49
|
+
['YV12', swapChroma],
|
|
50
|
+
],
|
|
51
|
+
BGRA: [['AR24', same]],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
class XvVideo {
|
|
55
|
+
constructor(app) {
|
|
56
|
+
this.app = app;
|
|
57
|
+
/** `undefined` while it is being asked for, then a VideoPort or null */
|
|
58
|
+
this.port = undefined;
|
|
59
|
+
this._opening = null;
|
|
60
|
+
/** the sizes asked about before the port answered, to lay out once it does */
|
|
61
|
+
this._waiting = [];
|
|
62
|
+
/** surface -> { target, window }: where each `<video>`'s frames go */
|
|
63
|
+
this._targets = new Map();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Start asking for a port, and — for a sink — for the layout of its
|
|
68
|
+
* frames, so its first frame is the only one drawn the slow way. Cheap
|
|
69
|
+
* and idempotent: a sink calls it when it is made.
|
|
70
|
+
*/
|
|
71
|
+
prepare(sink) {
|
|
72
|
+
if (this.port === undefined) {
|
|
73
|
+
if (sink) this._waiting.push(sink);
|
|
74
|
+
if (!this._opening) this._open();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (this.port && sink) this._layout(sink);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_open() {
|
|
81
|
+
this._opening = import('ntk/xv')
|
|
82
|
+
.then(({ openVideoPort }) => openVideoPort(this.app))
|
|
83
|
+
.catch(() => null)
|
|
84
|
+
.then((port) => {
|
|
85
|
+
// a port with nowhere to put a frame — no Composite, so no target —
|
|
86
|
+
// is no port: given back, and the formats are JavaScript's
|
|
87
|
+
if (port && !port.targets) {
|
|
88
|
+
port.close();
|
|
89
|
+
port = null;
|
|
90
|
+
}
|
|
91
|
+
this.port = port;
|
|
92
|
+
const waiting = this._waiting;
|
|
93
|
+
this._waiting = [];
|
|
94
|
+
if (port) for (const sink of waiting) this._layout(sink);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Ask the port how it lays out `sink`'s frames, if it takes them at all. */
|
|
99
|
+
_layout(sink) {
|
|
100
|
+
const choice = this._formatFor(sink);
|
|
101
|
+
if (choice) this.port.layout(choice[0], sink.width, sink.height);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* `preferredFormats` on X11 (src/videoframes.js): `null` while the port is
|
|
106
|
+
* being asked for — an answer not to keep — then the YCbCr formats the
|
|
107
|
+
* port takes ahead of BGRA, or BGRA alone where there is no port and every
|
|
108
|
+
* frame is drawn in JavaScript.
|
|
109
|
+
*/
|
|
110
|
+
videoFormats() {
|
|
111
|
+
if (this.port === undefined) {
|
|
112
|
+
this.prepare();
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
if (this.port === null) return ['BGRA'];
|
|
116
|
+
const takes = (name) =>
|
|
117
|
+
PORT_FORMATS[name].some(([format]) => this.port.formats.includes(format));
|
|
118
|
+
return [...['NV12', 'I420'].filter(takes), 'BGRA'];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The port's format for `sink` and how its planes go, or null where the
|
|
122
|
+
* port cannot show it as the sink means it. */
|
|
123
|
+
_formatFor(sink) {
|
|
124
|
+
const port = this.port;
|
|
125
|
+
if (sink.format !== 'BGRA') {
|
|
126
|
+
if (sink.range !== 'video') return null;
|
|
127
|
+
if (!port.colorSpaces.includes(sink.colorSpace)) return null;
|
|
128
|
+
}
|
|
129
|
+
return (
|
|
130
|
+
PORT_FORMATS[sink.format]?.find(([format]) =>
|
|
131
|
+
port.formats.includes(format),
|
|
132
|
+
) ?? null
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A `<video>`'s frame into `surface`, its drawn presentation: through the
|
|
138
|
+
* port into the node's target, then copied into the surface. False — and
|
|
139
|
+
* the node converts the frame itself — wherever this cannot (see the top).
|
|
140
|
+
*/
|
|
141
|
+
writeVideoFrame(surface, sink, frame, node) {
|
|
142
|
+
const port = this.port;
|
|
143
|
+
if (!port) {
|
|
144
|
+
if (port === undefined) this.prepare(sink);
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (port.closed) return false;
|
|
148
|
+
const choice = this._formatFor(sink);
|
|
149
|
+
const window = node?.root?.window;
|
|
150
|
+
if (!choice || !window || typeof window.id !== 'number') return false;
|
|
151
|
+
const [format, order] = choice;
|
|
152
|
+
const { width, height } = sink;
|
|
153
|
+
let kept = this._targets.get(surface);
|
|
154
|
+
if (kept && (kept.window !== window || kept.target.destroyed)) {
|
|
155
|
+
// the node is in another window now, or its window took the target
|
|
156
|
+
// with it
|
|
157
|
+
kept.target.destroy();
|
|
158
|
+
this._targets.delete(surface);
|
|
159
|
+
kept = undefined;
|
|
160
|
+
}
|
|
161
|
+
if (!kept) {
|
|
162
|
+
// the first frame of a size: asked, and drawn the other way meanwhile
|
|
163
|
+
if (!port.layout(format, width, height)) return false;
|
|
164
|
+
const target = port.createTarget(window, { width, height });
|
|
165
|
+
if (!target) return false;
|
|
166
|
+
kept = { target, window };
|
|
167
|
+
this._targets.set(surface, kept);
|
|
168
|
+
}
|
|
169
|
+
const sent = kept.target.put({
|
|
170
|
+
format,
|
|
171
|
+
width,
|
|
172
|
+
height,
|
|
173
|
+
planes: order(frame.planes),
|
|
174
|
+
strides: order(frame.strides),
|
|
175
|
+
colorSpace: sink.colorSpace,
|
|
176
|
+
});
|
|
177
|
+
if (!sent) return false;
|
|
178
|
+
kept.target.copyTo(surface);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** The node let `surface` go: so does its target. */
|
|
183
|
+
releaseVideoFrame(surface) {
|
|
184
|
+
const kept = this._targets.get(surface);
|
|
185
|
+
if (!kept) return;
|
|
186
|
+
this._targets.delete(surface);
|
|
187
|
+
kept.target.destroy();
|
|
188
|
+
}
|
|
189
|
+
}
|