Broiler.Hosting.Linux
0.1.0-preview.9
dotnet add package Broiler.Hosting.Linux --version 0.1.0-preview.9
NuGet\Install-Package Broiler.Hosting.Linux -Version 0.1.0-preview.9
<PackageReference Include="Broiler.Hosting.Linux" Version="0.1.0-preview.9" />
<PackageVersion Include="Broiler.Hosting.Linux" Version="0.1.0-preview.9" />
<PackageReference Include="Broiler.Hosting.Linux" />
paket add Broiler.Hosting.Linux --version 0.1.0-preview.9
#r "nuget: Broiler.Hosting.Linux, 0.1.0-preview.9"
#:package Broiler.Hosting.Linux@0.1.0-preview.9
#addin nuget:?package=Broiler.Hosting.Linux&version=0.1.0-preview.9&prerelease
#tool nuget:?package=Broiler.Hosting.Linux&version=0.1.0-preview.9&prerelease
Broiler.Hosting
Shared desktop and mobile hosting runtime, windowing services, input fidelity, and platform integration for the Broiler application suite (Broiler.Mail, Broiler.Code, Broiler.Writer, Broiler.Browser).
Components
Broiler.Hosting.Windows
Provides Windows desktop hosting facilities:
WindowsClipboard: Hardened Win32 clipboard integration with 1 MB UTF-16 bounds protection, strictGlobalSizevalidation, direct or lazy HWND owner resolution, and safe OS memory handoff.WindowsWindowSizing: Window sizing, minimum dimension enforcement (DPI-scaled client minimum 640x480) viaWM_GETMINMAXINFO, and dynamic multi-monitor DPI transition handling viaWM_DPICHANGED.WindowsTheme: System appearance inspection querying dark/light preference, Windows high contrast mode (SPI_GETHIGHCONTRAST), reduced motion preferences (SPI_GETCLIENTAREAANIMATION), and the "Make text bigger" text scale (TextScaleFactor, 1.0 to 2.25), exposingUiSystemSettings.ResolveTheme(UiSystemSettings)returns the standard preset, or in high contrast a palette built from the user's actual system colors (WindowsSystemColors,CreateHighContrastTheme): selected rows and selected text use the system highlight pair (SelectionTextisHighlightText), the palette is flaggedIsHighContrastand takes the settings' text scale, and a focus ring, link, or status color that blends into the window background falls back to the window text color. Text drawn in the accent (AccentText: the selected tab's label and the bar under it, accent labels, a themed toggle button's label at rest and hovered, inline codes) is the highlight color where that reads on the window color (4.5:1, as in all four Windows 11 contrast themes), and the window text color otherwise. It is the window text color as well where the highlight text is the window text, since a format code view then draws selected inline codes in it on the highlight color. Every scrollbar (ScrollbarTrack,ScrollbarThumb) draws its thumb in the window text color on a track of the window color, like every other control at rest in this palette. WinUI draws a thumb in the button text color, as it draws its buttons; Broiler.UI has no button roles, so where the button text is not the window text (Desert, Dusk, Night sky) these bars differ from the ones WinUI apps draw. The roles are set, so every copy of the palette keeps the bars, even one that clearsIsHighContrast. Broiler.UI has no hovered, pressed, or disabled thumb, which Windows draws in the highlight and gray text colors, so those look like the thumb at rest.WindowsSystemColors.Aquatic,Desert,Dusk, andNightSkyhold the Windows 11 contrast themes' colors, to build their palettes without changing the system's settings. Control states use the highlight pair too (StateFillisHighlight,StateTextisHighlightText): a hovered secondary button or spin box arrow, a checked, indeterminate, or pressed toggle button, and the open toolbar overflow button are drawn the way Windows 11 contrast themes draw UI that is hovered, pressed, or selected, and the code editor's matching bracket is marked with the highlight fill.ButtonFaceis the window color in all four of those themes, so a state drawn on it would look like the control at rest. Known gaps: Broiler.UI draws a pressed secondary button and a pressed spin box arrow onSurfaceDisabled, and a hovered unchecked toggle button onSurfaceAlt, not on the state fill; both are the window color here, as disabled and alternate surfaces need, so those states stay readable but look like the control at rest. Broiler.UI also draws in the accent, here the highlight color, directly on the window color: text (the label of a toggle button that was never themed, the code editor's keywords) and marks (a checked check box's fill and border, a checked radio button's dot, the progress bar's and slider's fill on their track, the list's unread dot, a window's or dialog's active border). That reads in the four Windows 11 themes, but not in a custom theme whose highlight color is close to its window color. And where the highlight text is the window text, a format code view draws selected codes other than inline codes in the link and status colors on the highlight color, where they need not read. A focused list strokes its focus ring, the highlight color, across its scrollbar's thumb, and a selected row's highlight fill meets the thumb; the two stand apart at only 1.4:1 to 1.9:1 in the four Windows 11 themes. A scroll view draws that stretch of its ring again in a color that stands out on the thumb; the list does not.WindowsTitleBar: Matches the native caption to a dark or light palette (DWMWA_USE_IMMERSIVE_DARK_MODE, Windows 10 build 19041 or later). Call it after the native window exists and whenever the palette changes.WindowsInputBridge: High-fidelity native input and scroll integration:- Top-level window activation focus handoff (
WM_SETFOCUSandWM_ACTIVATEtransferring Win32 focus to the render child HWND). - Exactly-once text delivery across
WM_CHARand IMM32 IME compositions (WM_IME_STARTCOMPOSITION,WM_IME_COMPOSITION, suppression of theWM_CHARcopiesDefWindowProcmakes of a commit passed on to it). - Inline composition (
DrawsCompositionInline, on by default):WM_IME_SETCONTEXTgoes on withoutISC_SHOWUICOMPOSITIONWINDOW, andWM_IME_STARTCOMPOSITIONand everyWM_IME_COMPOSITIONexcept one whose result string the bridge could not read are not passed toDefWindowProc, so the IME does not show the composition a second time in its own window and makes noWM_CHARcopies of a commit (the bridge expects none, so a character typed right after a commit is always typed). The IME's candidate list and guide still show. The setting covers the whole render window: while an element that draws no composition has the focus (a password field, a list, a tree, a menu, or a button), turn the IME off for the window. - Surrogate pair assembly (
\uD83D\uDE00) and stray surrogate cleanup. - Shortcut modifier isolation (
Ctrl+C,Ctrl+A,Ctrl+V,Ctrl+Z,Ctrl+Backspace,Ctrl+Entersuppressed from text generation) with fullAltGrand Alt+numpad support. Alt chords (WM_SYSCHAR, such asAlt+F) are never typed; they go on toDefWindowProc, which turns them intoSC_KEYMENU, soAlt+Spaceopens the window menu. This includes an Alt chord the application handled as a shortcut on key down: there is no way yet to mark one handled, so it also reachesDefWindowProc(which beeps for a letter no menu takes). - Sub-notch precision mouse wheel and horizontal tilt wheel handling (
WM_MOUSEWHEEL,WM_MOUSEHWHEEL). - Decoupled application-level input filtering hook (
Func<UiInputEvent, bool>?).
- Top-level window activation focus handoff (
WindowsAutomationBridge&WindowsElementAutomationPeer: Native Windows UI Automation (UIA) bridge:- Implements
IRawElementProviderFragmentRoot,IRawElementProviderFragment,IRawElementProviderSimple. - Maps Broiler UI controls to standard UIA patterns (
IInvokeProvider,IValueProvider,ISelectionProvider,ISelectionItemProvider,IToggleProvider,IExpandCollapseProvider,IScrollItemProvider, andITextProvider/ITextRangeProviderfor Edit and RichEdit text, by character, word, paragraph, and document, with search and selection; never for password fields). - A toggle button is a Button with the Toggle pattern and no Invoke, as its click is its toggle; a check box reports its state through Toggle as well. A window or dialog drawn inside the surface is a Pane, since the Window control type requires the Window and Transform patterns only the host window has, and a dialog reports
IsDialog. - Names come from the semantic name, never a type name; a field targeted by a label is named by that label and reports it as
LabeledBy, with its text as Value and its placeholder as HelpText. Unnamed layout containers are non-control elements, so the Control view shows their children directly. - Only the selected tab's content is exposed: inactive tab content is skipped in navigation and hit-testing and reported offscreen.
- Disclosure and validation (Broiler.UI ADR 0028): ExpandCollapse wherever the semantic state reports Expanded or Collapsed, acting through
IUiExpandableor the element'sDisclosestarget (the Cc/Bcc toggle of aFormSection), and throughUiTreeView.Expand/Collapsefor tree rows, which are exposed as tree items.ControllerForisControlswhile it is shown;IsDataValidForForm,IsRequiredForForm,DescribedBy(the shown error message first, then the description) andFullDescriptioncome from the field's control. Rows, tabs and tree rows answer both form properties as well, from the node their container describes them with (a row's presenter, the view's children): valid and not required unless that node says otherwise. UIA reportsIsDataValidForFormleft unanswered as false, so clients read every row and tab as not valid. A row's form properties are read when a client asks and raise no change event: nothing in Broiler.UI marks a row, tab or tree row invalid or required, and watching them would describe every row a client holds on each change of its container. The window's pane is no form field and answers valid and not required. - Trees: a tree's children are the rows Broiler.UI describes, those in view, and the focused row wherever it is, so the focus and its events always name a child of the tree; another row is not available, as a removed element is, and the selection lists only the selected rows that are children. A change to those rows (expanding, collapsing, moving the focus,
ScrollItem) raises oneChildrenInvalidatedon the tree when the dispatcher next runs. A wheel scroll that leaves the focus where it is reaches the bridge only with the tree's next state change, because Broiler.UI reports it as a render change alone. - Geometry: bounding rectangles are what can be seen, clipped to scroll viewports, list content and the window, and an element, row or tab with nothing in view is offscreen. List rows take their name and bounds from
UiListView.GetItemSemanticNode, tabs their header fromGetTabHeaderBounds, andElementProviderFromPointusesUiSession.HitTest(overlays such as an open drop-down win) with the same row and tab geometry; a point over another root of the session is the window's. - Runtime IDs are
[UiaAppendRuntimeId, n], allocated per bridge and never reused: an element keeps its ID for its lifetime, and a list row, tab or tree row keeps its ID by its item id, so rows inserted above a message never make its ID name another one. The hosted root leaves its ID to the window. - Focus:
SetFocuson a row or tab focuses its container without selecting;Selectdoes what a click does (focus the list or tab view, then select), so an application that moves focus when the selection changes keeps that decision under UI Automation too.AddToSelectionadds a row to a multiple-selection list and leaves the focus alone. Focus events name whatGetFocusreports, the selected row or tab of a focused container, andElementSelectedcomes once, from the container's change detection.Selectholds focus events until it returns, so a client hearsElementSelectedon the new row or tab and then oneFocusChanged, on it or on whatever the application's selection handler focused (none if the handler put the focus back where it was), never on the row selected before. That is what a COM client hears, whoseSelectreaches the provider asSelectalone. For a UIA2 client'sSelect(System.Windows.Automationand the tools built on it), UIAutomationCore first callsSetFocuson the item, as a call of its own, and sinceSetFocusdoes not select, that client hears the row selected before first.IsKeyboardFocusableisCanFocus, or having the focus; a row, tab or tree row reports it only while it is the item the focus is on (the selected one, or a tree's focused node) in a container that can take the focus, because Broiler.UI has no focused but unselected item.ProviderOwnsSetFocusis not declared, so UIA gives the host window the Win32 focus first. - This departs from Win32 and WinUI, whose list and tab items can hold the focus unselected and whose
Selectleaves the keyboard focus alone: hereSetFocuson an unselected item leaves the focus on the selected one, andSelectmoves the focus to the container first, in the order a click does, so that focus never stays inside tab content the new selection hides. - Change events are raised only for real differences (name, enabled state, value and text, text selection, list, tab or tree selection, expand state, toggle state, an element's validity, description). Structure changes are collected until the session's dispatcher next runs and raised once per changed parent a client has reached. That takes a dispatcher whose
Postruns later, such asStandardQueuedUiDispatcher: withImmediateUiDispatchereach change is raised at once, coalesced only as far as Broiler.UI batches the changes made duringDispatchInputandRenderFrame. - Lifetime: a peer whose element is removed or disposed, or whose row or tab is gone, answers native calls with
UIA_E_ELEMENTNOTAVAILABLE, as does every provider once the bridge is disposed or its window destroyed, at once rather than after a timeout.WM_DESTROYandDisposedisconnect every provider handed to UIA and release the window's providers. - Create the bridge with the handle of an existing window: with a
Direct2DWindow, inOnCreated. A zero handle attaches nothing and clients see an empty pane. The same applies toWindowsInputBridge. - Coordinate-free control and item tree navigation.
- Password protection ensuring sensitive fields never expose plain text through UIA.
UiSession.AnnounceStatusraises a UIA notification carrying the announced text, so clients read the status rather than the source element's name. Each source element is one activity: a newer status replaces one still queued, and an error (Invalidstate) is read before other speech. Status elements reportLiveSettingPolite, or Assertive while reporting an error. Without text, or on Windows before 10 1709, a live-region change is raised instead.
- Implements
Broiler.Hosting.Linux
Provides Linux desktop hosting facilities:
LinuxUiHost: ReusableIUiHostimplementation adaptingIBroilerRendererandIBroilerSurfaceto Broiler UI sessions, tracking viewport dimensions, DPI scale, frame indexing, and invalidations without double-scaling.LinuxX11Clipboard: Hardened X11 clipboard and primary selection host (IUiClipboardHost,IDisposable) with 1 MB payload limits,INCRstreaming, UTF-8/Latin-1 conversion, timeout bounds, and safe non-Linux execution guards.LinuxBackendDiagnostics: Preflight verification for X11/EGL/OpenGL dependencies (libEGL.so.1,libGL.so.1,libOpenGL.so.0,libX11.so.6,DISPLAY, architecture).LinuxInputCoordinator&LinuxInputSnapshot: Evdev input stream coordination unifying keyboard and mouse devices, merging modifier keys across separate evdev nodes, pointer clamping, and non-blocking event dispatch. SetQuitOnEscape = trueto have an Escape press raiseQuitRequestedfor the host loop (off by default).
Broiler.Hosting.Android
Provides Android hosting facilities with multi-targeting support (net10.0 for headless testing and net10.0-android36.0 for full runtime integration):
AndroidUiHost: ReusableIUiHost,IUiClipboardHost, andIUiTextInputHostadapter supportingAndroidBroilerView, direct delegates, or headless surface/renderer.AndroidBackendDiagnostics: Preflight check for Android runtime, architecture, and native graphic libraries (libEGL.so,libGLESv3.so,libandroid.so), with safe degradation on non-Android hosts.AndroidBroilerView: Hardware-acceleratedSurfaceViewwith Choreographer vsync loop, device lost recovery, density/viewport tracking, touch/hover/key routing, IME lifecycle, and clipboard glue.AndroidCanvasRenderer: Hardware-acceleratedIBroilerRendererreplaying display lists onto AndroidCanvasandPaintwith typeface caching.AndroidInputCoordinator: Unified coordinator routing touch contacts, pen contacts, key events, and IME text events intoUiInputEvents.AndroidInsetLayout:FrameLayouthandling display cutouts, navigation bars, and status bar insets.BroilerInputConnection:BaseInputConnectionbridging Android IME toAndroidTextInputDevice.
Architecture & Dependency Separation
Broiler.Hosting follows strict unidirectional dependency layering:
UI Abstractions + Graphics + Native Platform
│
▼
Broiler.Hosting.<Platform>
│
▼
Consumer Heads (Mail, Code, Writer, Browser)
Application-specific concerns (close/save guards, draft persistence, credential vaults, application commands) remain strictly outside the hosting component in the respective application layers.
Testing
dotnet test Broiler.Hosting.slnx
All unit tests in tests/Broiler.Hosting.Windows.Tests, tests/Broiler.Hosting.Linux.Tests, and tests/Broiler.Hosting.Android.Tests run headlessly and validate clipboard safety, sizing/DPI, system theme queries, input fidelity, backend diagnostics, and accessibility trees across platforms.
Publishing
CI (.github/workflows/ci.yml) builds and tests Release on Ubuntu and Windows, then on Windows packs and verifies every package, checks a fresh consumer restore of them from nuget.org (eng/verify-feed.ps1), and attaches them as nuget-packages. Publish (.github/workflows/publish.yml, manual or a v0.1.0-preview.N tag) resolves the next preview version (one past the highest 0.1.0-preview.N on nuget.org, see eng/resolve-preview-version.mjs), builds, tests, packs, verifies the consumer restore, and pushes the packages and their symbols to nuget.org with the NUGET_TOKEN (or NUGET_API_KEY) secret. Every Publish run pushes; there is no dry-run mode and no other feed. The no-push rehearsal is CI itself, on every push and pull request.
Documentation
- Release notes for 0.1.0-preview.8: opt-in Escape-to-quit on
LinuxInputCoordinator(QuitOnEscape,QuitRequested) and the X11 clipboard tests adopted from the applications. - Release notes for 0.1.0-preview.7: the release candidate of 5 October 2026 (not yet published; it requires Broiler.UI 0.1.0-preview.18), with compatibility notes for consumers, verification, and release steps.
- Open follow-ups, 5 October 2026: Hosting work left open by that round, including decisions for the owner and checks that need a person or hardware.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Broiler.Graphics (>= 0.1.0-preview.12)
- Broiler.Graphics.Linux (>= 0.1.0-preview.12)
- Broiler.Graphics.Linux.OpenGL (>= 0.1.0-preview.12)
- Broiler.Input (>= 0.1.0-preview.6)
- Broiler.Input.Keyboard (>= 0.1.0-preview.6)
- Broiler.Input.Keyboard.Linux (>= 0.1.0-preview.6)
- Broiler.Input.Linux (>= 0.1.0-preview.6)
- Broiler.Input.Mouse (>= 0.1.0-preview.6)
- Broiler.Input.Mouse.Linux (>= 0.1.0-preview.6)
- Broiler.Native (>= 0.1.0-preview.8)
- Broiler.Native.Linux (>= 0.1.0-preview.8)
- Broiler.UI (>= 0.1.0-preview.20)
- Broiler.UI.Standard (>= 0.1.0-preview.20)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-preview.9 | 0 | 10/11/2026 |
| 0.1.0-preview.8 | 144 | 10/7/2026 |
| 0.1.0-preview.7 | 77 | 10/5/2026 |
| 0.1.0-preview.6 | 62 | 10/4/2026 |
| 0.1.0-preview.5 | 100 | 10/3/2026 |
| 0.1.0-preview.4 | 84 | 10/2/2026 |
| 0.1.0-preview.3 | 64 | 10/2/2026 |
| 0.1.0-preview.2 | 57 | 10/2/2026 |
| 0.1.0-preview.1 | 57 | 10/2/2026 |