react-x11 2.52.0 → 2.53.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 (112) hide show
  1. package/README.md +10 -10
  2. package/docs/README.md +160 -314
  3. package/docs/accessibility.md +176 -229
  4. package/docs/appearance.md +77 -176
  5. package/docs/click-to-component.md +18 -51
  6. package/docs/clipboard.md +40 -59
  7. package/docs/components.md +518 -1036
  8. package/docs/dbus.md +61 -133
  9. package/docs/debugging.md +152 -245
  10. package/docs/desktop-calendar.md +51 -88
  11. package/docs/desktop.md +222 -347
  12. package/docs/devtools.md +50 -167
  13. package/docs/drag-and-drop.md +126 -204
  14. package/docs/ecosystem/animation.md +91 -125
  15. package/docs/ecosystem/data-fetching.md +38 -53
  16. package/docs/ecosystem/dev-tooling.md +159 -202
  17. package/docs/ecosystem/forms.md +61 -97
  18. package/docs/ecosystem/headless.md +64 -89
  19. package/docs/ecosystem/i18n.md +18 -21
  20. package/docs/ecosystem/icons.md +93 -126
  21. package/docs/ecosystem/layout.md +42 -52
  22. package/docs/ecosystem/routing.md +18 -29
  23. package/docs/ecosystem/state.md +71 -88
  24. package/docs/ecosystem/testing.md +131 -157
  25. package/docs/ecosystem/theming.md +119 -165
  26. package/docs/ecosystem.md +145 -179
  27. package/docs/elements.md +1091 -1774
  28. package/docs/embedding.md +83 -132
  29. package/docs/events.md +412 -695
  30. package/docs/extending.md +784 -1326
  31. package/docs/eyedropper.md +63 -122
  32. package/docs/filedialog.md +71 -107
  33. package/docs/frame.md +195 -339
  34. package/docs/gl.md +65 -62
  35. package/docs/globalmenu.md +63 -146
  36. package/docs/macos.md +531 -3234
  37. package/docs/notifications.md +33 -47
  38. package/docs/packaging.md +166 -309
  39. package/docs/permissions.md +9 -14
  40. package/docs/react-features.md +81 -106
  41. package/docs/remote.md +32 -76
  42. package/docs/scale.md +72 -186
  43. package/docs/styling.md +329 -547
  44. package/docs/system.md +200 -280
  45. package/docs/testing.md +63 -83
  46. package/docs/typescript.md +6 -48
  47. package/docs/uri-schemes.md +67 -107
  48. package/docs/wayland-backend.md +200 -459
  49. package/docs/windows-integrations.md +75 -131
  50. package/docs/windows.md +343 -1367
  51. package/package.json +3 -2
  52. package/src/Reconciler.js +2 -2
  53. package/src/a11y.js +1 -1
  54. package/src/backend/context2d.js +3 -3
  55. package/src/bootstrap.js +1 -1
  56. package/src/cocoa/app.js +6 -6
  57. package/src/cocoa/bezels.js +1 -1
  58. package/src/cocoa/fonts.js +1 -1
  59. package/src/cocoa/globalmenu.js +1 -1
  60. package/src/cocoa/keymap.js +1 -1
  61. package/src/cocoa/panewindow.js +1 -1
  62. package/src/cocoa/player.js +1 -1
  63. package/src/cocoa/presenter.js +2 -2
  64. package/src/cocoa/promotion.js +1 -1
  65. package/src/cocoa/relaunch.js +1 -1
  66. package/src/cocoa/threaded.js +1 -1
  67. package/src/cocoa/video.js +1 -1
  68. package/src/cocoa/window.js +4 -4
  69. package/src/components/Menu.js +7 -2
  70. package/src/components/Switch.js +1 -1
  71. package/src/components/native.js +1 -1
  72. package/src/dnd.js +2 -2
  73. package/src/glnodes.js +1 -1
  74. package/src/grid.js +1 -1
  75. package/src/layouts.js +1 -1
  76. package/src/nodes/animation.js +1 -1
  77. package/src/nodes/invalidate.js +1 -1
  78. package/src/nodes/layouthost.js +1 -1
  79. package/src/nodes/video.js +19 -8
  80. package/src/nodes/window/droptarget.js +1 -1
  81. package/src/pacing.js +1 -1
  82. package/src/refresh/index.js +2 -1
  83. package/src/types/video.d.ts +5 -2
  84. package/src/videobackend.js +28 -0
  85. package/src/videoframes.js +29 -16
  86. package/src/wayland/app.js +27 -0
  87. package/src/wayland/video.js +376 -0
  88. package/src/win32/a11y.js +1 -1
  89. package/src/win32/app.js +2 -2
  90. package/src/win32/fonts.js +1 -1
  91. package/src/win32/glarea.js +4 -4
  92. package/src/win32/overlay.js +1 -1
  93. package/src/win32/panewindow.js +3 -3
  94. package/src/win32/shell.js +1 -1
  95. package/src/win32/window.js +2 -2
  96. package/src/windowid.js +1 -1
  97. package/src/xvideo.js +189 -0
  98. package/docs/architecture/accessibility.md +0 -470
  99. package/docs/architecture/animation.md +0 -707
  100. package/docs/architecture/container-queries.md +0 -525
  101. package/docs/architecture/custom-layout.md +0 -334
  102. package/docs/architecture/drag-and-drop.md +0 -941
  103. package/docs/architecture/element-layer-contents.md +0 -622
  104. package/docs/architecture/frame-pacing.md +0 -255
  105. package/docs/architecture/grid-layout.md +0 -358
  106. package/docs/architecture/protocol-efficiency.md +0 -357
  107. package/docs/architecture/video.md +0 -1149
  108. package/docs/architecture/windowed-regions.md +0 -854
  109. package/docs/glx.md +0 -137
  110. package/docs/wayland.md +0 -545
  111. package/docs/windows-embedding.md +0 -271
  112. package/docs/windows-gl.md +0 -221
package/docs/embedding.md CHANGED
@@ -1,18 +1,16 @@
1
1
  # Embedding other applications: `<foreign>`
2
2
 
3
- > **X11 only.** Cross-process window embedding does not exist on macOS:
4
- > there is no way to take another application's window into your own view
5
- > hierarchy, and this is not a gap waiting to be filled — the platform does
6
- > not offer the primitive. On the Cocoa backend `<foreign>` refuses: it lays
7
- > out as an empty box, never calls `onReady`, and calls `onError` once — and
3
+ > **X11 only.** macOS offers no primitive for taking another application's
4
+ > window into your own. On the Cocoa backend `<foreign>` lays out as an empty
5
+ > box, never calls `onReady`, and calls `onError` once;
8
6
  > `useSupports('embedding')` is false there, so a component can ask before
9
- > rendering one. What does work there is [`<Frame>`](frame.md), which embeds
10
- > a pane of _your own_ application, and reaches the same place through
11
- > shared surfaces instead of reparenting.
7
+ > rendering one. [`<Frame>`](frame.md) does work there: it embeds a pane of
8
+ > _your own_ application through shared surfaces instead of reparenting.
12
9
 
13
- Everything else react-x11 draws, it draws itself. `<foreign>` is the one
14
- element that shows somebody else's pixels: another process's top-level X
15
- window, reparented into yours and laid out like any other child.
10
+ `<foreign>` is the one element that shows somebody else's pixels: another
11
+ process's top-level X window, reparented into yours and laid out like any
12
+ other child — a terminal pane, a video surface, a docked tray icon, a
13
+ control-panel applet.
16
14
 
17
15
  ```jsx
18
16
  <foreign
@@ -23,36 +21,27 @@ window, reparented into yours and laid out like any other child.
23
21
  />
24
22
  ```
25
23
 
26
- That is a terminal pane, a video surface, a docked tray icon and a
27
- control-panel applet — four things an application cannot draw for itself and
28
- has no business reimplementing.
29
-
30
- When the other process is a module of **your own application**, don't wire
31
- this up by hand: [`<Frame>`](frame.md) is `<foreign>` plus the process — the
32
- fork, the props, the callbacks, the bridged theme, the crash fallback. This
33
- page is the window half, and everything below about stacking, focus and
34
- teardown holds for a `<Frame>` pane too. The pane's own root window opts in
35
- with `<window embeddable>`: created **unmapped** — a window waiting to be
36
- embedded is unmapped, that is what waiting looks like — and mapped by the
37
- embedder once reparented. On X11 it is an XEmbed client for Tab: `FOCUS_IN`
38
- with `FIRST` or `LAST` lands on its first or last stop, and Tab off an end of
39
- its order sends `FOCUS_NEXT` or `FOCUS_PREV`, so Tab goes through a
40
- react-x11 guest as it goes through any subtree of the host's.
24
+ For a module of **your own application**, use [`<Frame>`](frame.md):
25
+ `<foreign>` plus the process — the fork, the props, the callbacks, the bridged
26
+ theme, the crash fallback. Everything below about stacking, focus and teardown
27
+ holds for a `<Frame>` pane too. The pane's root window opts in with
28
+ `<window embeddable>`: created **unmapped**, which is what waiting to be
29
+ embedded looks like, and mapped by the embedder once reparented. On X11 it
30
+ speaks XEmbed's Tab, so Tab goes through a react-x11 guest as through any
31
+ subtree of the host's.
41
32
 
42
33
  **Being the guest yourself** — a react-x11 app embedded in somebody else's UI
43
- — is that same prop plus one accessor: `windowHandleOf(ref)` (or
44
- `useWindowHandle(ref)`) is the number you hand the host, out of band, the way
45
- `xterm -into` is handed one. On X11 it is the window's XID and the host
46
- reparents it. On Windows it is a composition surface handle and the host
47
- binds it to a visual of its own, because a window there stops presenting the
48
- moment it becomes a child ([windows-embedding.md](windows-embedding.md) has
49
- the measurements). `null` means this backend has no way to be a guest — the
50
- capability, not a failure.
51
-
52
- The protocol underneath is [XEmbed](http://specifications.freedesktop.org/xembed/0.5/),
53
- implemented in ntk (`XEmbedSocket`, ntk ≥ 7.4.0). This page is the React half:
54
- what the element does, what it promises about a window it does not own, and
55
- what it does with the keyboard.
34
+ — is that same prop plus `windowHandleOf(ref)` (or `useWindowHandle(ref)`):
35
+ the number you hand the host, out of band, the way `xterm -into` is handed
36
+ one. On X11 it is the window's XID, which the host reparents. On Windows it is
37
+ a composition surface handle the host binds to a visual of its own, because a
38
+ window there stops presenting the moment it becomes a child
39
+ ([design notes](../design/windows-embedding.md)). `null` means this backend
40
+ has no way to be a guest — the capability, not a failure.
41
+
42
+ The protocol underneath is
43
+ [XEmbed](http://specifications.freedesktop.org/xembed/0.5/). Design notes:
44
+ [design/embedding.md](../design/embedding.md).
56
45
 
57
46
  ## Two ways in
58
47
 
@@ -79,9 +68,8 @@ is in it — that is the point.
79
68
  ## Most clients do not speak XEmbed
80
69
 
81
70
  `xterm -into`, `mpv --wid`, VLC and Wine set no `_XEMBED_INFO` and want plain
82
- reparenting. A missing property is not an error and not a fallback: it is the
83
- ordinary case, and it is what makes a terminal pane work at all. `onEmbedded`
84
- reports which happened:
71
+ reparenting. That is the ordinary case, not an error or a fallback, and it is
72
+ what makes a terminal pane work at all. `onEmbedded` reports which happened:
85
73
 
86
74
  ```jsx
87
75
  onEmbedded={({ id, xembed, version }) => { … }}
@@ -96,19 +84,11 @@ client is mapped and unmapped as its own `XEMBED_MAPPED` bit asks.
96
84
 
97
85
  Unmounting a `<foreign>` **reparents the client back to the root window and
98
86
  drops it from the save set. It never destroys it.** A React tree changing
99
- shape is not a reason for another application to lose its window, and the
100
- first test in `test/foreign.test.js` is there to keep it that way.
87
+ shape is not a reason for another application to lose its window.
101
88
 
102
89
  The same holds for `windowId` changing: the client that is leaving is handed
103
90
  back before the new one is taken.
104
91
 
105
- What this costs is an ordering rule, and it is the one thing worth knowing
106
- about the implementation: the reparent is issued **synchronously** during
107
- teardown, because `WindowNode` destroys its own X window in the same turn and
108
- `DestroyWindow` takes every inferior with it. The save set does not cover
109
- that — X processes it when a _connection_ closes, not when a window is
110
- destroyed.
111
-
112
92
  `onClientGone` fires when the client is destroyed by its own process, or
113
93
  reparented away by someone else. Nothing further is sent to a dead id.
114
94
 
@@ -116,32 +96,28 @@ reparented away by someone else. Nothing further is sent to a dead id.
116
96
 
117
97
  A released client is a top-level window again, and **a running window manager
118
98
  will manage it** — frame it, put it in the taskbar, place it wherever its
119
- policy says. That is the right outcome for an unmount (`examples/foreign.jsx`
120
- is built on it: detach the pane and the terminal is simply a terminal window
121
- on the desktop), and it is a trap for one thing:
99
+ policy says. That is right for an unmount (`examples/foreign.jsx` is built on
100
+ it: detach the pane and the terminal is simply a terminal window on the
101
+ desktop), and a trap for one thing:
122
102
 
123
103
  > **Do not hand a client from one `<foreign>` to another by unmounting the
124
104
  > first and mounting the second with the same `windowId`.**
125
105
 
126
- The window is parked at the root for the moment in between, which is long
127
- enough to be offered to the window manager. The WM's `ReparentWindow` into a
128
- frame of its own then arrives _after_ the second pane has taken the client,
129
- undoes it, and the second pane reports `onClientGone` — for a client that is
130
- alive and now framed on the desktop. It is a race with another process, so it
131
- does not always happen, which is worse than if it always did.
106
+ In between, the window is parked at the root long enough to be offered to the
107
+ window manager, whose reparent into a frame can arrive _after_ the second pane
108
+ has taken the client and undo it; the second pane then reports `onClientGone`
109
+ for a client that is alive and framed on the desktop. It is a race with
110
+ another process, so it does not always happen.
132
111
 
133
- Change `windowId` on **one** node instead. That path releases and re-embeds
134
- in order and is tested; the client is only ever at the root while nothing
135
- else wants it. (Re-embedding a window the WM has already framed also works —
136
- the reparent pulls it out and the WM unmanages it — the hazard is only the
137
- moment right after a release.)
112
+ Change `windowId` on **one** node instead: that path releases and re-embeds in
113
+ order. Re-embedding a window the WM has already framed also works — the
114
+ hazard is only the moment right after a release.
138
115
 
139
116
  ## Layout and stacking
140
117
 
141
118
  The rect comes from yoga like any other child, and every change moves the
142
- client and sends it the synthetic ICCCM 4.1.5 `ConfigureNotify` — root-relative
143
- coordinates, which is the question a client actually asks and which its own
144
- `ConfigureNotify` (relative to the container it now sits in) cannot answer.
119
+ client and tells it its root-relative position (the synthetic ICCCM
120
+ `ConfigureNotify`).
145
121
 
146
122
  Two consequences of it being a real X window, both shared with
147
123
  [`<glarea>`](elements.md#glarea):
@@ -154,29 +130,15 @@ Two consequences of it being a real X window, both shared with
154
130
  hit testing, which is exactly right for a terminal or a video surface.
155
131
 
156
132
  `backgroundColor` in the `style` is what shows in the rect before a client
157
- arrives and after one leaves — it is the container window's background, painted
158
- by the server. There is no separate prop for it, so the name is the one used
159
- everywhere else.
133
+ arrives and after one leaves — the container window's background, painted by
134
+ the server. There is no separate prop for it.
160
135
 
161
136
  ## Focus, and who gets the keys
162
137
 
163
- X gives the input focus to one window. XEmbed's answer is that the embedder
164
- holds the real focus and gives the client a _logical_ one by message, and the
165
- classic implementation of that is a **focus proxy**: an invisible InputOnly
166
- window that takes the X focus and forwards keystrokes into the client with
167
- `SendEvent`.
168
-
169
- **react-x11 does not use a proxy**, and the reason matters if you are reading
170
- the code expecting one:
171
-
172
- - A proxy inside our own toplevel means the toplevel sees `FocusOut` the moment
173
- the client is focused. react-x11 reads that as the window losing focus —
174
- carets stop blinking, `<window onBlur>` fires — and the element would be told
175
- to blur the client it had just focused.
176
- - A key that reaches a proxy has already gone past every handler in the React
177
- tree, so an application chord could never be checked first.
178
-
179
- So the X focus stays on your window, and the rule is:
138
+ X gives the input focus to one window. react-x11 keeps the X focus on your
139
+ window and gives the client a _logical_ focus by XEmbed message — no focus
140
+ proxy, which would make your window read the client's focus as its own blur
141
+ and let keys past every handler in the React tree. So the rule is:
180
142
 
181
143
  > While a `<foreign>` holds focus, the application's handlers see every key
182
144
  > first. Anything they do not consume is forwarded to the client.
@@ -205,32 +167,30 @@ Edit menu's, which is what a user of that terminal expects. An application
205
167
  chord that must win everywhere goes in an `onKeyDown` like the one above,
206
168
  which is checked before either.
207
169
 
208
- Everything else about focus is the ordinary focus manager:
209
-
210
- | what happens | what the client is told |
211
- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
212
- | the node takes focus by click or `focus()` | `XEMBED_WINDOW_ACTIVATE`, then `XEMBED_FOCUS_IN` detail `CURRENT` |
213
- | Tab into it | `FOCUS_IN` detail `FIRST` — focus your first widget |
214
- | Shift+Tab into it | `FOCUS_IN` detail `LAST` |
215
- | focus leaves, or the window deactivates | `FOCUS_OUT`, then `WINDOW_DEACTIVATE` |
216
- | the client sends `XEMBED_REQUEST_FOCUS` | the node is focused _through the focus manager_, so `:focus`, `:focus-within`, the previous node's `onBlur` and the AT-SPI bridge all see it |
217
- | the client sends `FOCUS_NEXT` / `FOCUS_PREV` | focus moves to the next/previous react-x11 focusable — Tab crosses the boundary as if it were one application |
170
+ Everything else about focus is the ordinary focus manager. Clicking or
171
+ `focus()`-ing the node activates the client and focuses it; Tab and Shift+Tab
172
+ into it focus its first or last widget; focus leaving, or the window
173
+ deactivating, unfocuses and deactivates it. A client asking for the focus
174
+ (`onRequestFocus`) is focused _through the focus manager_, so `:focus`,
175
+ `:focus-within`, the previous node's `onBlur` and the AT-SPI bridge all see
176
+ it. The XEmbed message behind each step is in the
177
+ [design notes](../design/embedding.md#focus-and-who-gets-the-keys).
218
178
 
219
179
  A `<foreign>` is focusable by default, like a `<textinput>`. `focusable={false}`
220
180
  opts out, which is what a video surface wants.
221
181
 
222
- Tab is _forwarded_ rather than acted on: an XEmbed client has a tab chain of its
223
- own and says so with `FOCUS_NEXT` when it runs off the end of it. A client that
224
- speaks no XEmbed — a terminal — keeps Tab for good, which is what a terminal is
225
- for; click elsewhere to leave.
182
+ Tab is _forwarded_ rather than acted on. An XEmbed client has a tab chain of
183
+ its own, and running off either end of it moves focus to the next or previous
184
+ react-x11 focusable — Tab crosses the boundary as if it were one application.
185
+ A client that speaks no XEmbed — a terminal — keeps Tab for good, which is
186
+ what a terminal is for; click elsewhere to leave.
226
187
 
227
188
  **Dead keys and Compose stay out of it.** react-x11's own composition
228
189
  ([events.md](events.md#composition)) does not run while a `<foreign>` holds
229
- focus: the client is another program with an input method of its own, and an
230
- accent composed on this side would swallow the `KeyPress` on its way there
231
- and hand back a character with nowhere to put it. The raw key is forwarded
232
- and the client composes it, which is also what makes `é` work in an embedded
233
- terminal whatever the toolkit inside it is.
190
+ focus: the client has an input method of its own, and an accent composed on
191
+ this side would swallow the key on its way there. The raw key is forwarded and
192
+ the client composes it, which is what makes `é` work in an embedded terminal
193
+ whatever the toolkit inside it is.
234
194
 
235
195
  ### The one gap
236
196
 
@@ -243,24 +203,22 @@ would make in the other direction.
243
203
  ## Reparenting window managers
244
204
 
245
205
  A `<foreign>` inside a toplevel that the window manager has reparented into a
246
- frame is offset by that frame, and the root-relative coordinates in the
247
- synthetic `ConfigureNotify` have to account for it. react-x11 tracks the
248
- toplevel's screen origin from `ReparentNotify`/`ConfigureNotify` and asks the
249
- server rather than trusting reported geometry — the same problem
250
- `src/components/anchor.js` solves for popup placement.
206
+ frame is offset by that frame. react-x11 tracks the toplevel's screen origin
207
+ and tells the client its true root-relative position; nothing is needed from
208
+ the app.
251
209
 
252
210
  ## Props
253
211
 
254
- | prop | |
255
- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
256
- | `windowId` | the X window to embed. Changing it hands the old client back first. Omit it to adopt whatever is put inside the node instead. |
257
- | `onReady` | `({ windowId })` — the node's own container id, offered before anything is embedded, to spawn a program into |
258
- | `onEmbedded` | `({ id, xembed, version })` — a client is in |
259
- | `onClientGone` | destroyed, or reparented away by someone else |
260
- | `onRequestFocus` | the client asked for the focus (it is then given through the focus manager) |
261
- | `onError` | the embed failed — no such window, or it went away mid-handshake. Without a handler, a console warning. |
262
- | `focusable` | default `true`; takes part in the focus manager and the tab chain |
263
- | `style` | layout as usual; `backgroundColor` is what shows with no client in |
212
+ | prop | |
213
+ | ---------------- | -------------------------------------------------------------------------------------------------------------- |
214
+ | `windowId` | the X window to embed; a change hands the old client back first. Omit to adopt whatever is put inside the node |
215
+ | `onReady` | `({ windowId })` — the node's own container id, before anything is embedded, to spawn a program into |
216
+ | `onEmbedded` | `({ id, xembed, version })` — a client is in |
217
+ | `onClientGone` | destroyed, or reparented away by someone else |
218
+ | `onRequestFocus` | the client asked for the focus (then given through the focus manager) |
219
+ | `onError` | the embed failed — no such window, or it went away mid-handshake; without a handler, a console warning |
220
+ | `focusable` | default `true`; takes part in the focus manager and the tab chain |
221
+ | `style` | layout as usual; `backgroundColor` shows with no client in |
264
222
 
265
223
  ## Example
266
224
 
@@ -275,14 +233,7 @@ FOREIGN_CMD="mpv --wid=%WID% video.mp4" npm run examples:foreign
275
233
 
276
234
  ## What is not here yet
277
235
 
278
- - **`<TrayHost>`** — owning the `_NET_SYSTEM_TRAY_S<screen>` manager selection
279
- and rendering a `<foreign>` per docked icon, which is what makes a react-x11
280
- panel a real desktop shell. The system tray is XEmbed's biggest surviving
281
- consumer.
236
+ - **`<TrayHost>`** — hosting other applications' tray icons (owning the
237
+ system tray selection, a `<foreign>` per docked icon).
282
238
  - **The plug side** — a react-x11 root that renders _into_ someone else's
283
- socket, for shipping as a tray icon or a panel applet. Lower value and
284
- deliberately last: GTK4 removed `GtkPlug` and Qt dropped `QX11Embed*` after
285
- Qt4, so the population of hosts willing to embed us is shrinking while the
286
- population of clients we can host is not.
287
-
288
- Both are tracked in [issue #269](https://github.com/sidorares/react-x11/issues/269).
239
+ XEmbed socket, as a tray icon or a panel applet.