react-x11 2.51.1 → 2.52.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 +87 -54
- package/docs/README.md +410 -0
- package/docs/accessibility.md +628 -0
- package/docs/appearance.md +416 -0
- package/docs/architecture/accessibility.md +470 -0
- package/docs/architecture/animation.md +707 -0
- package/docs/architecture/container-queries.md +525 -0
- package/docs/architecture/custom-layout.md +334 -0
- package/docs/architecture/drag-and-drop.md +941 -0
- package/docs/architecture/element-layer-contents.md +622 -0
- package/docs/architecture/frame-pacing.md +255 -0
- package/docs/architecture/grid-layout.md +358 -0
- package/docs/architecture/protocol-efficiency.md +357 -0
- package/docs/architecture/video.md +1149 -0
- package/docs/architecture/windowed-regions.md +854 -0
- package/docs/click-to-component.md +125 -0
- package/docs/clipboard.md +281 -0
- package/docs/components.md +1749 -0
- package/docs/dbus.md +277 -0
- package/docs/debugging.md +464 -0
- package/docs/desktop-calendar.md +284 -0
- package/docs/desktop.md +648 -0
- package/docs/devtools.md +250 -0
- package/docs/drag-and-drop.md +663 -0
- package/docs/ecosystem/animation.md +394 -0
- package/docs/ecosystem/data-fetching.md +201 -0
- package/docs/ecosystem/dev-tooling.md +436 -0
- package/docs/ecosystem/forms.md +313 -0
- package/docs/ecosystem/headless.md +219 -0
- package/docs/ecosystem/i18n.md +89 -0
- package/docs/ecosystem/icons.md +410 -0
- package/docs/ecosystem/layout.md +216 -0
- package/docs/ecosystem/routing.md +146 -0
- package/docs/ecosystem/state.md +361 -0
- package/docs/ecosystem/testing.md +500 -0
- package/docs/ecosystem/theming.md +540 -0
- package/docs/ecosystem.md +473 -0
- package/docs/elements.md +2762 -0
- package/docs/embedding.md +288 -0
- package/docs/events.md +1025 -0
- package/docs/extending.md +2242 -0
- package/docs/eyedropper.md +223 -0
- package/docs/filedialog.md +258 -0
- package/docs/frame.md +580 -0
- package/docs/gl.md +170 -0
- package/docs/globalmenu.md +278 -0
- package/docs/glx.md +137 -0
- package/docs/macos.md +3295 -0
- package/docs/notifications.md +164 -0
- package/docs/packaging.md +611 -0
- package/docs/permissions.md +148 -0
- package/docs/react-features.md +430 -0
- package/docs/remote.md +223 -0
- package/docs/scale.md +339 -0
- package/docs/security.md +132 -0
- package/docs/styling.md +1928 -0
- package/docs/system.md +599 -0
- package/docs/testing.md +514 -0
- package/docs/typescript.md +117 -0
- package/docs/uri-schemes.md +380 -0
- package/docs/wayland-backend.md +591 -0
- package/docs/wayland.md +545 -0
- package/docs/windows-embedding.md +271 -0
- package/docs/windows-gl.md +221 -0
- package/docs/windows-integrations.md +233 -0
- package/docs/windows.md +1404 -0
- package/package.json +9 -2
- package/src/bus.js +39 -26
- package/src/cli/create.d.ts +43 -0
- package/src/cli/create.js +305 -0
- package/src/cli/env.js +484 -0
- package/src/cli/index.js +29 -2
- package/src/cli/templates/AGENTS.template.md +195 -0
- package/src/cli/templates/DESIGN.template.md +269 -0
- package/src/desktopintegration.js +2 -1
- package/src/desktopsettings.js +193 -24
- package/src/filedialog.js +3 -3
- package/src/keyboardstate.js +28 -0
- package/src/node.d.ts +10 -10
- package/src/portal.js +31 -0
- package/src/screencolor.js +5 -10
- package/src/types/system.d.ts +8 -6
- package/src/wayland/app.js +59 -0
- package/src/wayland/clipboard.js +14 -7
- package/src/wayland/connection.js +3 -0
- package/src/wayland/context2d.js +129 -10
- package/src/wayland/protocols/index.json +6 -0
- package/src/wayland/protocols/xdg-foreign-unstable-v2.json +1 -0
- package/src/wayland/seat.js +28 -1
- package/src/wayland/swapchain.js +23 -0
- package/src/wayland/xkb.js +137 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Desktop integration on Windows: what works, and what does not
|
|
2
|
+
|
|
3
|
+
[windows.md](windows.md) is the design: what the backend is for and how it is
|
|
4
|
+
built. This is the status — what an app running on `@windowkit/win32` can
|
|
5
|
+
actually reach today, what it cannot, and which of the gaps have a route.
|
|
6
|
+
|
|
7
|
+
Everything below was measured on this backend rather than inferred from the
|
|
8
|
+
API's existence. "Works" means a test asserts it or it was driven and seen.
|
|
9
|
+
|
|
10
|
+
## Works
|
|
11
|
+
|
|
12
|
+
| what | the API | how |
|
|
13
|
+
| ------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
14
|
+
| a window, composed | `<window>` | DirectComposition surface per window, Direct2D verbs |
|
|
15
|
+
| text and layout | `<text>`, `app.fonts` | DirectWrite: layout, line metrics, hit testing, carets |
|
|
16
|
+
| glyph runs | `ctx.drawGlyphs`, `face.glyphIdFor`/`advanceOf` | `DrawGlyphRun` — what `<Terminal backend="vt">` positions its grid with |
|
|
17
|
+
| variable font axes | `style.variations` | `IDWriteTextLayout4::SetFontAxisValues` |
|
|
18
|
+
| app-supplied fonts | `loadFont`, `openFont` | a DirectWrite font set of the app's own, with the file's axes kept |
|
|
19
|
+
| OpenGL | `<glarea>` | WGL, and `WGL_NV_DX_interop2` to reach the composed surface |
|
|
20
|
+
| keyboard | `onKeyDown`, focus | `ToUnicodeEx` without consuming dead keys; X keysym vocabulary |
|
|
21
|
+
| pointer | `onMouseDown`, wheel, capture | all five buttons, `SetCapture` for drags leaving the window |
|
|
22
|
+
| focus | `onFocus`/`onBlur` | `WM_ACTIVATE` |
|
|
23
|
+
| window states | `useWindowState`, `<window maximized fullscreen alwaysOnTop>` | `ShowWindow`, `SetWindowPos`, a remembered frame for fullscreen |
|
|
24
|
+
| screens and DPI | `useScreens`, `useScale` | per-monitor v2; `WM_DPICHANGED` |
|
|
25
|
+
| light/dark and accent | `useSystemAppearance` | `UISettings` and the theme registry; the frame follows through `DWMWA_USE_IMMERSIVE_DARK_MODE` |
|
|
26
|
+
| native control bezels | `<button>`, `<checkbox>`… | the visual styles engine, where its dark variants are real — measured, not assumed |
|
|
27
|
+
| file dialogs | `useFileDialog` | the Common Item Dialog, parented, modal on the UI thread |
|
|
28
|
+
| clipboard | `useClipboard` | text and format enumeration |
|
|
29
|
+
| tray icon and menu | `useTray` | `Shell_NotifyIcon` |
|
|
30
|
+
| taskbar progress | `useProgress` | `ITaskbarList3::SetProgressValue` |
|
|
31
|
+
| a badge on the icon | `useBadge`, `setBadge` | the count drawn into an overlay icon — Windows has no badge API |
|
|
32
|
+
| demanding attention | `setUrgent` | `FlashWindowEx` |
|
|
33
|
+
| global hotkeys | `useAccelerator` | `RegisterHotKey` |
|
|
34
|
+
| notifications | `notify`, `useNotifier` | a tray balloon, which the shell shows as a toast |
|
|
35
|
+
| idle time | `useIdle` | `GetLastInputInfo`, polled on the same adaptive wait the X rung uses |
|
|
36
|
+
| keeping the screen awake | `keepAwake`, `useKeepAwake` | `SetThreadExecutionState`, counted |
|
|
37
|
+
| reading a window back | `window.snapshot()` | `PrintWindow` with `PW_CLIENTONLY | PW_RENDERFULLCONTENT` |
|
|
38
|
+
| locale | `systemLocale`, `useLocale` | ICU's own resolution, which reads the OS on Windows — no backend code |
|
|
39
|
+
| drag and drop | `useDropTarget`, `useDragSource` | `IDropTarget` and `DoDragDrop` over OLE, both directions |
|
|
40
|
+
| a thumbnail toolbar | `useThumbnailToolbar` | `ITaskbarList3::ThumbBarAddButtons` — **Windows only** |
|
|
41
|
+
| a jump list | `useJumpList` | `ICustomDestinationList` — **Windows only** |
|
|
42
|
+
| recent documents | `useRecentDocument` | `SHAddToRecentDocs` — **Windows only** |
|
|
43
|
+
| input methods | `onCompositionStart`/`Update`/`End`, `<textinput>` | IMM32: the preedit is drawn in the field, the candidate list follows the caret |
|
|
44
|
+
| screen readers | `role`, `aria-*`, `announce()` | a UI Automation provider over a pushed mirror of the tree |
|
|
45
|
+
| window identity | `<window appId>` | the AppUserModelID on the window's property store — taskbar grouping, pinning, the jump list |
|
|
46
|
+
|
|
47
|
+
## Built, with limits worth knowing
|
|
48
|
+
|
|
49
|
+
### Input methods — built on IMM32, with the gaps that layer has
|
|
50
|
+
|
|
51
|
+
CJK input works: `WM_IME_*` reaches `src/win32/ime.js`, which drives the same
|
|
52
|
+
composition events a Wayland text-input drives, so an application handles one
|
|
53
|
+
composition and gets both. The preedit is drawn **in the field** rather than
|
|
54
|
+
in a floating box, and the candidate list follows the caret.
|
|
55
|
+
|
|
56
|
+
What it does not carry is what IMM32 itself no longer carries. Windows has
|
|
57
|
+
stopped loading IMM32 input methods, so every modern one — the new Microsoft
|
|
58
|
+
Japanese and Chinese IMEs included — is a TSF text service reaching an IMM32
|
|
59
|
+
window through a compatibility layer, and that layer does not pass on **voice
|
|
60
|
+
typing** (Win+H inserts nothing), the shell's **handwriting** panel, or
|
|
61
|
+
**shape-writing** on the touch keyboard. A TSF text store is what closes
|
|
62
|
+
those; windows.md §"IME" has the design and why it is the harder rung.
|
|
63
|
+
|
|
64
|
+
Reconversion (asking the IME to re-open a committed word) is not wired up
|
|
65
|
+
either, though IMM32 carries it.
|
|
66
|
+
|
|
67
|
+
### Screen readers — built, without text ranges
|
|
68
|
+
|
|
69
|
+
`WM_GETOBJECT` is answered by a UI Automation provider of this project's own
|
|
70
|
+
(`windows/src/uia.cc`), served from a mirror `src/win32/a11y.js` pushes. Roles,
|
|
71
|
+
names, descriptions, states, bounding rectangles, focus and the Invoke, Toggle,
|
|
72
|
+
Value and RangeValue patterns all cross; `announce()` goes out as a UIA
|
|
73
|
+
notification. Everything an app writes — `role`, `aria-label`, `aria-checked`,
|
|
74
|
+
`aria-valuenow` — is read from `src/a11y.js`, the same pure functions the
|
|
75
|
+
AT-SPI bridge reads, so the two backends cannot disagree about what a node is.
|
|
76
|
+
|
|
77
|
+
The mirror is the deliberate part. UIA's calls are synchronous and frequent —
|
|
78
|
+
one focus change is dozens of property reads — so answering them from the live
|
|
79
|
+
tree would pace the screen reader by the app's busiest moment. windows.md
|
|
80
|
+
§"Accessibility: UI Automation" has the argument; it named AccessKit as the
|
|
81
|
+
reuse candidate for the same shape, and a provider of our own was built
|
|
82
|
+
instead so the release pipeline does not grow a Rust toolchain for both
|
|
83
|
+
architectures.
|
|
84
|
+
|
|
85
|
+
**What is missing is `ITextProvider`.** A `<textinput>` exposes its value, so a
|
|
86
|
+
screen reader reads the field and hears edits, but caret-by-caret and
|
|
87
|
+
word-by-word navigation _inside_ it is not there. That is the next piece.
|
|
88
|
+
|
|
89
|
+
## Not implemented
|
|
90
|
+
|
|
91
|
+
Ordered by what it costs an app today.
|
|
92
|
+
|
|
93
|
+
### `useLauncherMenu` is inert
|
|
94
|
+
|
|
95
|
+
The jump list is built (`useJumpList` above) but it is **not** what
|
|
96
|
+
`useLauncherMenu` means, and is deliberately not wired to it. A launcher-menu
|
|
97
|
+
item carries a callback; a jump-list task starts a _new process_ with arguments,
|
|
98
|
+
because the shell launches the program rather than calling into the running
|
|
99
|
+
one. Mapping one onto the other would quietly change what a click does.
|
|
100
|
+
|
|
101
|
+
They become the same feature once a second launch can hand its arguments to
|
|
102
|
+
the first, which is the activation work below.
|
|
103
|
+
|
|
104
|
+
### Activation — file associations, URL schemes, second launches
|
|
105
|
+
|
|
106
|
+
`useAppOpen` and `useAppActivate` fire on macOS and through the freedesktop
|
|
107
|
+
transport on Linux. On Windows an app has to register its associations under
|
|
108
|
+
`HKCU\Software\Classes`, declare an AppUserModelID, and make the second launch
|
|
109
|
+
hand its arguments to the first and exit — a named mutex and a `WM_COPYDATA`,
|
|
110
|
+
or `ISingleInstanceApp`. [uri-schemes.md](uri-schemes.md) documents what the
|
|
111
|
+
other platforms do.
|
|
112
|
+
|
|
113
|
+
### Eyedropper — the pixel is read, the ladder has no rung
|
|
114
|
+
|
|
115
|
+
The bridge reads a screen pixel through GDI (`app.screenColorAt`,
|
|
116
|
+
`app.pointerPosition`), but `src/screencolor.js` has no rung that calls it,
|
|
117
|
+
so `useEyedropper()` reports `supported: false` here until one draws the
|
|
118
|
+
loupe over it.
|
|
119
|
+
|
|
120
|
+
### Calendar — blocked, not missing
|
|
121
|
+
|
|
122
|
+
`useDesktopCalendarEvents` wants the Windows appointments API, which requires
|
|
123
|
+
package identity. Unpackaged, there is nothing to call, and the hook reports
|
|
124
|
+
`supported: false` rather than guessing.
|
|
125
|
+
|
|
126
|
+
### Permissions — nothing to ask
|
|
127
|
+
|
|
128
|
+
`usePermission` has no Windows meaning for an unpackaged app: the capability
|
|
129
|
+
API is for packaged apps, and everything else sits under one per-device switch.
|
|
130
|
+
The honest answer is `'unknown'` until something is attempted and the attempt's
|
|
131
|
+
own error is the answer.
|
|
132
|
+
|
|
133
|
+
### Global menu — not a Windows concept
|
|
134
|
+
|
|
135
|
+
`useGlobalMenu` is a menu bar owned by the desktop. Windows has none; a
|
|
136
|
+
`<MenuBar>` drawn in the window is the whole story here, and that works.
|
|
137
|
+
|
|
138
|
+
### Keyboard grabs
|
|
139
|
+
|
|
140
|
+
`grabKeyboard` accepts and does nothing: there is no Windows mechanism for it,
|
|
141
|
+
and nothing in the tree reads its result. A popup that asked for keys gets them
|
|
142
|
+
only while it is the foreground window.
|
|
143
|
+
|
|
144
|
+
`grabPointer` is a different story — see below.
|
|
145
|
+
|
|
146
|
+
## Built, with limits worth knowing: `<popup grab>`
|
|
147
|
+
|
|
148
|
+
A menu closing when you click beside it is what the pointer grab is _for_, and
|
|
149
|
+
Windows has no grab to give: `SetCapture` sends a window the mouse only while a
|
|
150
|
+
button is already down, so a press that starts elsewhere never arrives. The
|
|
151
|
+
effect is reproduced from two signals instead, and `<Select>`, `<Menu>` and any
|
|
152
|
+
`<popup grab>` dismiss the way they do everywhere else:
|
|
153
|
+
|
|
154
|
+
- a press delivered to **another window of this application** — a click in the
|
|
155
|
+
owner behind the menu, in a second window, or in the menu a submenu came
|
|
156
|
+
from;
|
|
157
|
+
- the application **losing activation** — a press in another application or on
|
|
158
|
+
the desktop. A popup is `WS_EX_NOACTIVATE`, so it never takes activation
|
|
159
|
+
itself and opening one raises no blur.
|
|
160
|
+
|
|
161
|
+
Both end in the same made-up outside press the Wayland backend sends for
|
|
162
|
+
`xdg_popup.popup_done`, and the Cocoa backend's grab rule redirects a press to
|
|
163
|
+
the holder the same way, so all four backends answer a dismissal through one
|
|
164
|
+
path (`_dismissOutside` in src/events.js).
|
|
165
|
+
|
|
166
|
+
**The gap**: a press on the _non-client_ area of one of our own windows — a
|
|
167
|
+
title bar, a resize border. The bridge does not report those, so a menu left
|
|
168
|
+
open while the user drags the window behind it stays open. X11's grab covers
|
|
169
|
+
that and this does not.
|
|
170
|
+
|
|
171
|
+
## What Windows has that nothing else does
|
|
172
|
+
|
|
173
|
+
Things with no cross-platform API to fit into. Three of them now have one of
|
|
174
|
+
their own, and the rule that makes that safe is worth stating once: **a backend
|
|
175
|
+
installs a method, and its presence is the capability**. They are reported as
|
|
176
|
+
features of the launcher, beside the badge and the progress bar:
|
|
177
|
+
|
|
178
|
+
```jsx
|
|
179
|
+
const launcher = useDesktopCapability('launcher');
|
|
180
|
+
launcher.backend; // 'taskbar' here, 'cocoa' on a Dock
|
|
181
|
+
launcher.features.thumbnailToolbar; // the buttons under the hover preview
|
|
182
|
+
launcher.features.tasks; // the jump list's Tasks category
|
|
183
|
+
launcher.features.recentDocuments; // the shell's Recent lists
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
They live there rather than in `useSupports()` because `useSupports` answers
|
|
187
|
+
for the **display** — transparency, shaders, embedding — and a taskbar button
|
|
188
|
+
is not a display property; and because a boolean cannot say _which_ launcher
|
|
189
|
+
answered, which is the whole reason capabilities carry a `backend` and a
|
|
190
|
+
feature map. Every other backend answers false for the three without knowing
|
|
191
|
+
Windows exists, and the hooks do nothing where the method is absent.
|
|
192
|
+
`examples/taskbar.jsx` is the shape; there is no `process.platform` in it.
|
|
193
|
+
|
|
194
|
+
- ~~**Thumbnail toolbars.**~~ Built: `useThumbnailToolbar`. Up to seven buttons
|
|
195
|
+
under the taskbar thumbnail — play/pause/next for a media app. The Dock has
|
|
196
|
+
nothing like it; the closest sibling is the macOS Touch Bar, which is gone.
|
|
197
|
+
- **A custom taskbar thumbnail and peek.** `DWM_THUMBNAIL_PROPERTIES` and
|
|
198
|
+
`WM_DWMSENDICONICTHUMBNAIL` let an app answer the hover preview with
|
|
199
|
+
something other than a shrunken window — a document's first page, a chart.
|
|
200
|
+
- **Tabbed thumbnails.** One taskbar entry per document with
|
|
201
|
+
`ITaskbarList4::SetTabProperties`, which is how browsers put tabs on the
|
|
202
|
+
taskbar.
|
|
203
|
+
- ~~**Recent documents.**~~ Built: `useRecentDocument`.
|
|
204
|
+
- **Explorer verbs.** "Open with", a context-menu handler, a preview handler,
|
|
205
|
+
a thumbnail provider. All of these are COM servers registered per file type,
|
|
206
|
+
and on Windows 11 a context-menu handler must be a packaged app extension —
|
|
207
|
+
which puts them behind packaging along with the calendar.
|
|
208
|
+
- **Protocol activation.** `myapp://` as a first-class launch, which is the
|
|
209
|
+
activation work above seen from the other side.
|
|
210
|
+
- **Taskbar overlay as a status light.** Already reachable: `setBadge` takes a
|
|
211
|
+
label, and an app that wants a dot rather than a number can pass one
|
|
212
|
+
character.
|
|
213
|
+
|
|
214
|
+
## What would fit this library and exists nowhere yet
|
|
215
|
+
|
|
216
|
+
Not Windows-specific — gaps in the cross-platform surface that Windows happens
|
|
217
|
+
to be able to answer.
|
|
218
|
+
|
|
219
|
+
- **A print dialog and a print surface.** No backend has one. Windows has
|
|
220
|
+
`PrintDlgEx` and the XPS document API; macOS has `NSPrintOperation`;
|
|
221
|
+
freedesktop has the portal. A `<Print>` surface that takes the same verb
|
|
222
|
+
table the screen does is a natural fit for a renderer that already draws
|
|
223
|
+
through one.
|
|
224
|
+
- **A colour chooser.** `useEyedropper` samples a pixel; nothing offers the
|
|
225
|
+
system's colour picker. `IColorPickerDialog` (WinUI), `NSColorPanel` and the
|
|
226
|
+
portal all exist.
|
|
227
|
+
- **A font chooser.** `IDWriteFontSet` plus the Common Item Dialog's
|
|
228
|
+
chooser, `NSFontPanel`, the portal's.
|
|
229
|
+
- **Session lifecycle.** `WM_QUERYENDSESSION` and `WM_ENDSESSION` on Windows,
|
|
230
|
+
`NSApplicationDelegate` on macOS, the session manager on Linux — an app that
|
|
231
|
+
wants to save before logout has no hook on any backend.
|
|
232
|
+
- **Power and battery.** `GetSystemPowerStatus`, `IOPowerSources`, UPower.
|
|
233
|
+
A `useBattery` would be one hook over three.
|