Repository navigation
feat: setCursor, GDI face names (fontFamilyOf), font width, letter spacing, OpenType features and x-height for react-x11's Windows text engine - #14
Merged
Conversation
…ient area, where the class cursor was the arrow everywhere and react-x11 asked for a cursor nothing answered A name maps to the system's cursors — the link hand, the I-beam, the resize arrows, wait, not-allowed — and `none` hides it. The window answers WM_SETCURSOR over its client area with the cursor last set, and shows it at once where the pointer is already there, since the move that changed what is under it has been answered by then. react-x11 calls it for every window and every <Frame> pane's host, and called it into nothing: no link in a document ever showed the hand on Windows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
… and a face take a width, a span its letter spacing and OpenType features, and a face's metrics carry its x-height and cap height — where Arial Black and Segoe UI Light fell back to the default face, `letter-spacing` was set tight and an `ex` had no face to be measured in - `fontFamilyOf(name)`: a name the system collection has no family by, looked up as GDI looks a face name up (`CreateFontFromLOGFONT`), and answered as the family DirectWrite files the face under and the face's weight, width and slope. DirectWrite groups faces by those three, so the families a Windows user knows by name — Arial Black, Arial Narrow, Segoe UI Light, Franklin Gothic Medium — are faces of others here, and every other Windows program, Chrome among them, finds them. - A width (`stretch`, 1–9) on `layoutCreate`'s options and spans, and as the fifth argument of `fontMetrics` and `fontHandle`: what reaches a narrow face. - `letterSpacing` on a span, through `SetCharacterSpacing`, and `features` by tag, through an `IDWriteTypography`. - `xHeight` and `capHeight` from `fontMetrics`, what CSS's `ex` and `cap` are measured in. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This was referenced Oct 4, 2026
sidorares
added a commit
to sidorares/react-x11
that referenced
this pull request
Oct 4, 2026
…ce names, font widths, letter spacing, OpenType features, x-heights and DirectWrite's justification (#879) The range admitted 0.0.7 alone (a caret on 0.0.x is exact), so what #874 asks the bridge for was answered by none: no link showed the hand on Windows, Arial Black and Segoe UI Light fell back to the default face, a `letter-spacing` was set tight and an `ex` had no face to be measured in. 0.0.8 (windowkit/win32#14) and 0.0.9 (windowkit/win32#16, the justification and the min-content width on request #878 switches on). Co-authored-by: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found running
@react-x11/components' browser example on Windows for the first time. react-x11 asked the bridge for things it did not have, and a page differed from Chrome's in ways a reader sees at once. Each item here is one of those.Cursor
setCursor(windowId, name)maps a CSS cursor name to a system cursor: the link hand, the I-beam, the resize arrows, wait, not-allowed.nonehides the cursor. The window answersWM_SETCURSORover its client area with the cursor last set. Where the pointer is already over the window, the new cursor shows at once, since the move that changed what's under it was answered before the name arrived.react-x11 already calls
native.setCursor?.(id, name)for every window and for every<Frame>pane's host, but the class cursor wasIDC_ARROWand nothing answered. No link ever showed the hand on Windows. I checked this with the real pointer: hand over a link, I-beam over text, crosshair where a page sets one, arrow elsewhere, both in a window and through a<Frame>pane.Text
fontFamilyOf(name)looks up a name the system collection has no family for, the way GDI does (CreateFontFromLOGFONT). It answers{ family, weight, stretch, italic }. DirectWrite groups faces by weight, width and slope, so Arial Black, Arial Narrow, Segoe UI Light and Franklin Gothic Medium are faces of other families, andfontExistssays no to each. Chrome finds them all, and a page naming one fell back to the default face.stretch, 1–9): onlayoutCreate's options and spans, and as the fifth argument offontMetricsandfontHandle. This is what reaches a narrow face. It's part of the handle cache key.letterSpacingon a span, throughIDWriteTextLayout1::SetCharacterSpacing. Without it, CSSletter-spacingcame out tight, and react-x11's<Html>, which justifies through letter spacing when the engine can't justify itself, left every justified paragraph ragged.featureson a span,{ smcp: 1, liga: 0 }by tag, through anIDWriteTypography.xHeightandcapHeightfromfontMetrics: what CSS'sexandcapunits are measured in.Tests
test/text.jscovers the GDI lookup (Segoe UI Semibold → Segoe UI 600, an unknown name → null), the width on handles and spans, letter spacing (five characters at 2 px each come out 10 px wider), features, and the new metrics.npm run test:unitandnpm run test:windowpass locally on Windows 11.The react-x11 half is in the core PR that follows this one. It feature-detects
fontFamilyOfand is harmless against 0.0.7.Still open (not in this PR)
Under a
lineHeight,layoutCreateuses proportional spacing with the baseline at0.8 × multiple. At a multiple of 1 that puts the baseline at 80% of the face's. react-x11 now reads the ascent and descent the bridge measures, so<Html>compensates, but core's own<text>still draws high in its line box under a line height. That's for a follow-up.🤖 Generated with Claude Code