Haiku BMediaTheme: Parameter Controls, View Factories, and Fallbacks
Build Haiku BMediaTheme controls around parameter webs while preserving view ownership, fallback behavior, theme lifetime, and current selection limits.
BMediaTheme connects a Media Kit BParameterWeb to Interface Kit controls. A theme can construct a view for a parameter web and a control for a parameter, allowing applications to present media-node settings without hard-coding every control layout. It complements the parameter model; it does not replace it. The node remains responsible for parameter identity, value validation, timing, and notification semantics.
The base class is abstract. A concrete theme implements MakeViewFor() and MakeControlFor(), and may also provide names, information, IDs, and an add-on reference. Static helpers such as ViewFor(), SetPreferredTheme(), and PreferredTheme() provide the selection boundary. Because theme objects and views are dynamically allocated, ownership must be explicit at each point.
Separate parameter schema from presentation
The BParameterWeb defines groups and controls that a media node exposes. A theme maps those descriptions into BView and BControl objects. A custom view should use the parameter’s type, range, channel, and label information to choose an appropriate widget, but the widget must still send changes through the supported media control path. Do not let the visual control become the source of truth for the actual node value.
BView* controls = BMediaTheme::ViewFor(web, &preferredRect);
if (controls == NULL)
return B_NO_MEMORY;
status_t status = parent->AddChild(controls);
if (status != B_OK) {
delete controls;
return status;
}
This demonstrates the view factory and one possible ownership handoff into a parent view. Confirm the exact ownership convention of the parent API used by your application and do not delete a child after the parent has taken ownership. If view construction fails partway through, release temporary controls and avoid returning a partially initialized subtree as though it were complete.
Keep parameter IDs attached to controls through an explicit association or message payload. Labels are for people and may be localized; they are not stable identifiers. When a parameter web changes, rebuild or update the UI through the documented change path and invalidate stale control references. A custom theme should not cache a raw BParameter* indefinitely if the web can be replaced.
Build fallbacks and unsupported control cases
BMediaTheme::ViewFor() uses a preferred theme if none is supplied. The current implementation creates a default theme when necessary, and if no theme is available it returns a placeholder view that says no theme is available. Theme consumers should still check the returned pointer and test a fallback scenario rather than assuming the factory always creates a complete control panel.
MakeFallbackViewFor() exists as a protected helper for a basic control. Use it deliberately when a custom theme does not support a parameter type, or reject the parameter and show a clear explanation. Do not fabricate a slider for an enum or structured parameter simply because the UI needs something visible. Unsupported presentation must not silently imply that the parameter is safe to edit.
The base class exposes background and foreground hooks. Inspect the current implementation before relying on them: some base methods are unimplemented or return generic UI colors. A subclass should provide any visual behavior it truly requires and remain legible under different system appearance settings. Never assume a theme color is available as a bitmap unless the implementation says so.
Make selection and lifetime explicit
SetPreferredTheme() accepts a BMediaTheme* and the current implementation takes ownership of the object, including when the selection operation fails. Do not pass a stack object or delete the selected theme independently. When resetting to the default with a null pointer, the implementation creates or restores a default theme. Keep the theme alive while views depend on it, and avoid swapping global preference while callbacks are still constructing controls.
The current implementation also contains TODO notes about persisting the preferred theme and discovering an add-on from a global settings file. Therefore, do not promise that a call to SetPreferredTheme() creates a system-wide persistent user preference or automatically loads a theme add-on. The API entry points for a theme add-on include make_theme() and get_theme_at() under the add-on build define, but packaging and discovery must follow the actual target system’s implementation.
For add-on release testing, verify both the theme metadata enumeration and instance creation functions against the exact loader expected by the supported Haiku release. A source-level exported function does not prove that a package is installed in a discoverable location or that the runtime will load it. Keep the default theme usable when enumeration returns no custom choices, and report the selected theme ID and source reference in diagnostics.
Store the add-on entry_ref as diagnostic metadata rather than proof that the theme is still installed. Before attempting a reload, resolve the reference and handle missing files. If a theme disappears while an app remains open, existing views may still be alive, but future construction can fail; define whether the app falls back to the default or disables the control panel.
Keep UI work off media-critical callbacks
Theme view construction and control updates belong to the Interface Kit lifecycle. Do not create or mutate views from a real-time audio callback. If the media node changes a parameter, notify through the Media Kit mechanism and have the UI apply the new display state on its own looper. If a user changes a control, validate and send the value through the node’s defined parameter contract.
Avoid lock inversion between the media parameter web and a window lock. Copy the data needed for presentation while holding the appropriate web lock, release it, then create or update UI elements. A panel that holds a window lock while calling into a node can deadlock if the node’s notification path tries to touch that same window.
Compatibility and accessibility
Test parameter type changes, missing parameters, long localized names, empty webs, narrow windows, large system fonts, and theme replacement while a panel is open. Preserve keyboard traversal, labels, and accessible descriptions. A custom slider should show its unit or meaningful range when applicable; an unlabelled numeric value is not a usable control contract.
Treat add-on version compatibility separately from parameter schema compatibility. A theme may load while failing to understand a new parameter type. Keep a fallback path for unknown controls and avoid dereferencing incomplete add-on state. If a theme crashes during view creation, the application should contain the failure where possible and preserve the underlying media graph.
Keep the theme’s control factory deterministic. Given the same parameter metadata and hint rectangle, it should create equivalent controls and avoid registering hidden background work each time a panel opens. Store transient UI state in the view or its controller, not in global static theme state that survives longer than one window. If the same theme constructs views in multiple applications, ensure instance data is not mutated unsafely across those call sites.
Use Name(), Info(), ID(), and GetRef() for diagnostics and selection metadata, but do not treat a display name as a unique identifier. The integer ID and add-on reference have separate meanings in the API. Keep a support log that records which theme object was selected and whether the parameter-specific factory returned a usable control. This makes it possible to distinguish a bad media node web from a missing theme or a broken widget implementation.
Acceptance criteria
Accept a BMediaTheme integration when it maps the parameter web without replacing node semantics, transfers each view and theme ownership exactly once, has an unsupported-type fallback, avoids UI work in media callbacks, and does not assume preference persistence or add-on discovery beyond the current implementation. Verify teardown and live web changes.
BMediaTheme is a presentation adapter for media controls. The node’s parameter contract, theme availability, persistence, and view lifetime remain separate responsibilities.
Related:
- Haiku BParameterWeb: Describing Typed Controls on Media Nodes
- Haiku BControllable: Parameter State, Timed Changes, and Notifications
Sources: