react-x11 2.51.1 → 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 (121) hide show
  1. package/README.md +94 -61
  2. package/docs/README.md +256 -0
  3. package/docs/accessibility.md +575 -0
  4. package/docs/appearance.md +317 -0
  5. package/docs/click-to-component.md +92 -0
  6. package/docs/clipboard.md +262 -0
  7. package/docs/components.md +1231 -0
  8. package/docs/dbus.md +205 -0
  9. package/docs/debugging.md +371 -0
  10. package/docs/desktop-calendar.md +247 -0
  11. package/docs/desktop.md +523 -0
  12. package/docs/devtools.md +133 -0
  13. package/docs/drag-and-drop.md +585 -0
  14. package/docs/ecosystem/animation.md +360 -0
  15. package/docs/ecosystem/data-fetching.md +186 -0
  16. package/docs/ecosystem/dev-tooling.md +393 -0
  17. package/docs/ecosystem/forms.md +277 -0
  18. package/docs/ecosystem/headless.md +194 -0
  19. package/docs/ecosystem/i18n.md +86 -0
  20. package/docs/ecosystem/icons.md +377 -0
  21. package/docs/ecosystem/layout.md +206 -0
  22. package/docs/ecosystem/routing.md +135 -0
  23. package/docs/ecosystem/state.md +344 -0
  24. package/docs/ecosystem/testing.md +474 -0
  25. package/docs/ecosystem/theming.md +494 -0
  26. package/docs/ecosystem.md +439 -0
  27. package/docs/elements.md +2079 -0
  28. package/docs/embedding.md +239 -0
  29. package/docs/events.md +742 -0
  30. package/docs/extending.md +1700 -0
  31. package/docs/eyedropper.md +164 -0
  32. package/docs/filedialog.md +222 -0
  33. package/docs/frame.md +436 -0
  34. package/docs/gl.md +173 -0
  35. package/docs/globalmenu.md +195 -0
  36. package/docs/macos.md +592 -0
  37. package/docs/notifications.md +150 -0
  38. package/docs/packaging.md +468 -0
  39. package/docs/permissions.md +143 -0
  40. package/docs/react-features.md +405 -0
  41. package/docs/remote.md +179 -0
  42. package/docs/scale.md +225 -0
  43. package/docs/security.md +132 -0
  44. package/docs/styling.md +1710 -0
  45. package/docs/system.md +519 -0
  46. package/docs/testing.md +494 -0
  47. package/docs/typescript.md +75 -0
  48. package/docs/uri-schemes.md +340 -0
  49. package/docs/wayland-backend.md +332 -0
  50. package/docs/windows-integrations.md +177 -0
  51. package/docs/windows.md +380 -0
  52. package/package.json +11 -3
  53. package/src/Reconciler.js +2 -2
  54. package/src/a11y.js +1 -1
  55. package/src/backend/context2d.js +3 -3
  56. package/src/bootstrap.js +1 -1
  57. package/src/bus.js +39 -26
  58. package/src/cli/create.d.ts +43 -0
  59. package/src/cli/create.js +305 -0
  60. package/src/cli/env.js +484 -0
  61. package/src/cli/index.js +29 -2
  62. package/src/cli/templates/AGENTS.template.md +195 -0
  63. package/src/cli/templates/DESIGN.template.md +269 -0
  64. package/src/cocoa/app.js +6 -6
  65. package/src/cocoa/bezels.js +1 -1
  66. package/src/cocoa/fonts.js +1 -1
  67. package/src/cocoa/globalmenu.js +1 -1
  68. package/src/cocoa/keymap.js +1 -1
  69. package/src/cocoa/panewindow.js +1 -1
  70. package/src/cocoa/player.js +1 -1
  71. package/src/cocoa/presenter.js +2 -2
  72. package/src/cocoa/promotion.js +1 -1
  73. package/src/cocoa/relaunch.js +1 -1
  74. package/src/cocoa/threaded.js +1 -1
  75. package/src/cocoa/video.js +1 -1
  76. package/src/cocoa/window.js +4 -4
  77. package/src/components/Menu.js +7 -2
  78. package/src/components/Switch.js +1 -1
  79. package/src/components/native.js +1 -1
  80. package/src/desktopintegration.js +2 -1
  81. package/src/desktopsettings.js +193 -24
  82. package/src/dnd.js +2 -2
  83. package/src/filedialog.js +3 -3
  84. package/src/glnodes.js +1 -1
  85. package/src/grid.js +1 -1
  86. package/src/keyboardstate.js +28 -0
  87. package/src/layouts.js +1 -1
  88. package/src/node.d.ts +10 -10
  89. package/src/nodes/animation.js +1 -1
  90. package/src/nodes/invalidate.js +1 -1
  91. package/src/nodes/layouthost.js +1 -1
  92. package/src/nodes/video.js +19 -8
  93. package/src/nodes/window/droptarget.js +1 -1
  94. package/src/pacing.js +1 -1
  95. package/src/portal.js +31 -0
  96. package/src/refresh/index.js +2 -1
  97. package/src/screencolor.js +5 -10
  98. package/src/types/system.d.ts +8 -6
  99. package/src/types/video.d.ts +5 -2
  100. package/src/videobackend.js +28 -0
  101. package/src/videoframes.js +29 -16
  102. package/src/wayland/app.js +86 -0
  103. package/src/wayland/clipboard.js +14 -7
  104. package/src/wayland/connection.js +3 -0
  105. package/src/wayland/context2d.js +129 -10
  106. package/src/wayland/protocols/index.json +6 -0
  107. package/src/wayland/protocols/xdg-foreign-unstable-v2.json +1 -0
  108. package/src/wayland/seat.js +28 -1
  109. package/src/wayland/swapchain.js +23 -0
  110. package/src/wayland/video.js +376 -0
  111. package/src/wayland/xkb.js +137 -0
  112. package/src/win32/a11y.js +1 -1
  113. package/src/win32/app.js +2 -2
  114. package/src/win32/fonts.js +1 -1
  115. package/src/win32/glarea.js +4 -4
  116. package/src/win32/overlay.js +1 -1
  117. package/src/win32/panewindow.js +3 -3
  118. package/src/win32/shell.js +1 -1
  119. package/src/win32/window.js +2 -2
  120. package/src/windowid.js +1 -1
  121. package/src/xvideo.js +189 -0
@@ -0,0 +1,239 @@
1
+ # Embedding other applications: `<foreign>`
2
+
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;
6
+ > `useSupports('embedding')` is false there, so a component can ask before
7
+ > rendering one. [`<Frame>`](frame.md) does work there: it embeds a pane of
8
+ > _your own_ application through shared surfaces instead of reparenting.
9
+
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.
14
+
15
+ ```jsx
16
+ <foreign
17
+ windowId={terminal.windowId}
18
+ style={{ flexGrow: 1, backgroundColor: '#101014' }}
19
+ onEmbedded={({ xembed }) => setMode(xembed ? 'xembed' : 'reparented')}
20
+ onClientGone={() => respawn()}
21
+ />
22
+ ```
23
+
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.
32
+
33
+ **Being the guest yourself** — a react-x11 app embedded in somebody else's UI
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).
45
+
46
+ ## Two ways in
47
+
48
+ **You have a window id.** Pass it as `windowId`. The client is added to the
49
+ save set, reparented into the node's own X window, sized to the node's rect
50
+ and told where it is.
51
+
52
+ **You are about to start the program.** Then there is no id yet — a program
53
+ like `xterm -into WID` or `mpv --wid=WID` has to be _given_ a window before it
54
+ makes one. Leave `windowId` out, and the node adopts whatever turns up inside
55
+ it; `onReady` hands you the id to spawn into:
56
+
57
+ ```jsx
58
+ <foreign
59
+ style={{ flexGrow: 1 }}
60
+ onReady={({ windowId }) => spawn('xterm', ['-into', String(windowId)])}
61
+ onClientGone={() => close(paneId)}
62
+ />
63
+ ```
64
+
65
+ `onReady` fires as soon as the node has an X window, which is before anything
66
+ is in it — that is the point.
67
+
68
+ ## Most clients do not speak XEmbed
69
+
70
+ `xterm -into`, `mpv --wid`, VLC and Wine set no `_XEMBED_INFO` and want plain
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:
73
+
74
+ ```jsx
75
+ onEmbedded={({ id, xembed, version }) => { … }}
76
+ ```
77
+
78
+ `xembed: false` means plain reparenting — the client was mapped immediately
79
+ and no `_XEMBED` messages will pass. `xembed: true` means the client answered,
80
+ `version` is the protocol version both sides settled on, and from then on the
81
+ client is mapped and unmapped as its own `XEMBED_MAPPED` bit asks.
82
+
83
+ ## The window is not yours
84
+
85
+ Unmounting a `<foreign>` **reparents the client back to the root window and
86
+ drops it from the save set. It never destroys it.** A React tree changing
87
+ shape is not a reason for another application to lose its window.
88
+
89
+ The same holds for `windowId` changing: the client that is leaving is handed
90
+ back before the new one is taken.
91
+
92
+ `onClientGone` fires when the client is destroyed by its own process, or
93
+ reparented away by someone else. Nothing further is sent to a dead id.
94
+
95
+ ### Letting go really means letting go
96
+
97
+ A released client is a top-level window again, and **a running window manager
98
+ will manage it** — frame it, put it in the taskbar, place it wherever its
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:
102
+
103
+ > **Do not hand a client from one `<foreign>` to another by unmounting the
104
+ > first and mounting the second with the same `windowId`.**
105
+
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.
111
+
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.
115
+
116
+ ## Layout and stacking
117
+
118
+ The rect comes from yoga like any other child, and every change moves the
119
+ client and tells it its root-relative position (the synthetic ICCCM
120
+ `ConfigureNotify`).
121
+
122
+ Two consequences of it being a real X window, both shared with
123
+ [`<glarea>`](elements.md#glarea):
124
+
125
+ - **Nothing drawn can overlap it.** A child X window is stacked above
126
+ everything painted in its parent. An overlay — a HUD, a "reconnecting…"
127
+ banner — belongs in a sibling `<popup>`. `<foreign>` takes no children and
128
+ says so rather than laying out something that could never be seen.
129
+ - **Pointer events over it are the client's.** They never reach react-x11's
130
+ hit testing, which is exactly right for a terminal or a video surface.
131
+
132
+ `backgroundColor` in the `style` is what shows in the rect before a client
133
+ arrives and after one leaves — the container window's background, painted by
134
+ the server. There is no separate prop for it.
135
+
136
+ ## Focus, and who gets the keys
137
+
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:
142
+
143
+ > While a `<foreign>` holds focus, the application's handlers see every key
144
+ > first. Anything they do not consume is forwarded to the client.
145
+
146
+ `preventDefault()` is how they consume it — the same word, and the same
147
+ ordering, that lets a `<textinput>` keep Tab as an indent key:
148
+
149
+ ```jsx
150
+ <window
151
+ onKeyDown={(ev) => {
152
+ if (ev.ctrlKey && ev.keysym === XK_t) {
153
+ ev.preventDefault(); // the app's chord; the terminal never sees it
154
+ newTab();
155
+ }
156
+ }}
157
+ >
158
+ <foreign windowId={id} style={{ flexGrow: 1 }} />
159
+ </window>
160
+ ```
161
+
162
+ **A menu accelerator is not a handler**, and this is the one place that shows.
163
+ [Accelerators](events.md#accelerators) run _after_ the focused element's own
164
+ default action, and `<foreign>`'s is to forward the key and consume it — so
165
+ while an embedded terminal has focus its Ctrl+C is the terminal's, not the
166
+ Edit menu's, which is what a user of that terminal expects. An application
167
+ chord that must win everywhere goes in an `onKeyDown` like the one above,
168
+ which is checked before either.
169
+
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).
178
+
179
+ A `<foreign>` is focusable by default, like a `<textinput>`. `focusable={false}`
180
+ opts out, which is what a video surface wants.
181
+
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.
187
+
188
+ **Dead keys and Compose stay out of it.** react-x11's own composition
189
+ ([events.md](events.md#composition)) does not run while a `<foreign>` holds
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.
194
+
195
+ ### The one gap
196
+
197
+ X delivers a key to the deepest descendant of the focus window that contains the
198
+ pointer. So while the pointer is _over_ the embedded client, the client receives
199
+ keys directly and no handler of yours runs — application chords do not work
200
+ there. They work everywhere else in the window, which is the trade a focus proxy
201
+ would make in the other direction.
202
+
203
+ ## Reparenting window managers
204
+
205
+ A `<foreign>` inside a toplevel that the window manager has reparented into a
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.
209
+
210
+ ## Props
211
+
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 |
222
+
223
+ ## Example
224
+
225
+ `examples/foreign.jsx` spawns a program into a pane and then lets go of it,
226
+ which is the whole element in one click: the pane disappears and the terminal
227
+ is still there, framed by the window manager, as if it had started on its own.
228
+
229
+ ```sh
230
+ npm run examples:foreign # xterm, if you have it
231
+ FOREIGN_CMD="mpv --wid=%WID% video.mp4" npm run examples:foreign
232
+ ```
233
+
234
+ ## What is not here yet
235
+
236
+ - **`<TrayHost>`** — hosting other applications' tray icons (owning the
237
+ system tray selection, a `<foreign>` per docked icon).
238
+ - **The plug side** — a react-x11 root that renders _into_ someone else's
239
+ XEmbed socket, as a tray icon or a panel applet.