Skip to content

feat(plugins): canvases can read the plugin theme - #210

Merged
eriknihlen merged 1 commit into
eriknihlen:mainfrom
davidc-smith:feat/plugin-theme-api-upstream
Oct 8, 2026
Merged

eriknihlen merged 1 commit into
eriknihlen:mainfrom
davidc-smith:feat/plugin-theme-api-upstream

Conversation

@davidc-smith

Copy link
Copy Markdown
Contributor

What this changes

A plugin canvas paints its own pixels, so it is never told which theme the
player picked under Plugin appearance. Markup windows that opt in with
theme="plugin" are restyled by the client, but a HUD drawn on a canvas stays
in one fixed look whatever the player chose, and can't change when they switch.

This adds the selected theme to the plugin contract:

  • IUiRegistry.Theme: a PluginUiThemeInfo with the theme's Kind
    (Classic, Moss, Brass), the DisplayName the picker shows, and its
    Palette, the seven colours themed windows draw in as PluginColors
    (null under Classic).
  • IUiRegistry.ThemeChanged: raised on the tick thread, once per change,
    with the new theme.

How it is bound:

  • Graphical client: BufferedUiRegistry.FollowTheme follows
    PluginUiThemeSettings from the moment RetailUiRuntime mounts plugins,
    so plugins read the saved theme as soon as the interface is up. It keeps
    the last theme across a reconnect. A handler that throws is logged and does
    not stop other plugins from hearing.
  • Both clients: the scoped registry forwards Theme and tracks each
    ThemeChanged handler like any other registration, so a plugin's handlers
    are removed when it unloads.
  • Windowless client: answers PluginUiThemeInfo.Classic and never
    raises a change.

Additive: both members have inert defaults, so a host that predates this
answers Classic. The picker's theme names now live in one place
(PluginUiThemeSettings.ThemeNames), shared by PluginAppearanceBinding.

Documented in a new "Plugin theme" section of docs/plugin-api.md, with a
pointer from the appearance section of docs/plugin-ui-markup.md.

Tested by PluginThemeContractTests (inert defaults),
ScopedUiRegistryThemeTests (forwarding, removal, unload),
BufferedUiRegistryThemeTests (palette values, picker names, publish/follow,
throwing handlers) and a headless surface test (Classic without a window).

Original behavior

No change to what the client does in the world. This only exposes the
existing plugin appearance preference to plugins.

Checklist

  • dotnet build AcDream.slnx -c Release is green
  • The portable test filter passes locally (see CONTRIBUTING.md). The
    exceptions are four HostParity Peer* IPC parity tests, which time out on
    this Mac on clean main too.
  • One topic per PR
  • No code copied from ACEmulator, ACViewer, or holtburger
  • No comments describing the original client's internals

https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw

A canvas paints its own pixels, so it was never told which plugin theme
the player picked under Plugin appearance and could only draw one fixed
look. IUiRegistry now carries the selected theme (kind, picker name and
palette as PluginColors) and raises ThemeChanged on the plugin callback
thread when the player picks another.

The graphical host follows PluginUiThemeSettings through
BufferedUiRegistry.FollowTheme, so plugins read the saved theme from the
moment the interface comes up. The scoped registry both hosts share
forwards the theme and drops a plugin's handlers with the plugin. The
windowless host answers Classic and never raises a change.

Additive with inert defaults: a host that predates this answers Classic.

Claude-Session: https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw
@eriknihlen
eriknihlen merged commit e8c7670 into eriknihlen:main Oct 8, 2026
3 of 7 checks passed
@davidc-smith
davidc-smith deleted the feat/plugin-theme-api-upstream branch October 10, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants