Custom plug-in UI, base layer: concepts, editor seam, gestures, message bus#161
Open
jcelerier wants to merge 8 commits into
Open
Custom plug-in UI, base layer: concepts, editor seam, gestures, message bus#161jcelerier wants to merge 8 commits into
jcelerier wants to merge 8 commits into
Conversation
This was referenced Jul 6, 2026
1e33dce to
dcf66fa
Compare
1e2e816 to
5afa08b
Compare
avnd::gui_windowed_ui (T::ui::window with open/close/idle/size), avnd::gui_parent / gui_host (host parent handle + automation-gesture fn-ptr protocol: flat param index, normalized [0,1]), and avnd::make_ui_editor which resolves, in order: the author-provided Tier C window, then — only when a target is built with a soft-UI backend (AVND_SOFT_UI_EDITOR) — the reference editor for declarative layouts. Architecture plan in CUSTOM_UI_PLAN.md. Co-Authored-By: Claude Fable 5 <[email protected]>
ui::bus / Tier C send_message/process_message endpoints over moodycamel queues: UI thread enqueues (may allocate), audio thread try_enqueues on preallocated storage and never blocks. avnd::bus_serial handles non-trivially-copyable payloads (string/vector/aggregate); payloads a serializer can't handle silently disable that bus direction, by design. Co-Authored-By: Claude Fable 5 <[email protected]>
Editors resolve through avnd::make_ui_editor (author-provided Tier C window, or the reference editor when a soft-UI backend is enabled at build time). Automation gestures flow editor -> lock-free gesture queue -> host params request_flush -> CLAP_EVENT_PARAM_GESTURE_BEGIN / PARAM_VALUE / GESTURE_END in params.flush. The message bus rides the same lock-free transport, drained in process() on the audio side and on the editor timer on the UI side. Co-Authored-By: Claude Fable 5 <[email protected]>
Same editor resolution and bus transport as the CLAP binding; automation gestures map to audioMaster BeginEdit/Automate/EndEdit and processor->UI messages drain on EditIdle and the editor frame hook. Co-Authored-By: Claude Fable 5 <[email protected]>
- plug_view drives an avnd::gui_windowed_ui editor: controller-side model instance, IComponentHandler begin/perform/endEdit gestures, IPlugViewContentScaleSupport, and a UI-thread tick (Win32 SetTimer / host IRunLoop on Linux / CFRunLoopTimer on macOS) that runs editor->idle() and the bus pump. - The message bus crosses the component/controller split via IMessage with the pfr serializer; IMessage is only allocated/sent on the UI thread (see the bus.hpp header comment for the pump protocol), the audio thread only enqueues. - The prototype defines the plug-view + Linux windowing IIDs (IRunLoop, ITimerHandler, IEventHandler): an unresolved reference to any of them would pull commoniids.cpp.o out of libsdk_common.a, which then collides with every DEF_CLASS_IID under GNU ld. Co-Authored-By: Claude Fable 5 <[email protected]>
CustomUiWindow: a gain with a hand-rolled editor (raw Win32 + GDI on Windows, raw Xlib on Linux) through the avnd::gui_windowed_ui seam — no UI library at all, so the contract is the whole story. Tested through the CLAP binding by tests/ui/test_custom_ui_window.cpp: embed in a real parent window, injected drag, gesture flow, message-bus round trip. tests/ui/gui_test_host.hpp is the shared Win32/X11 host layer (parent window, event pump with per-tick host callback, child discovery, synthetic input, PPM capture) that the soft-editor tests reuse later. Co-Authored-By: Claude Fable 5 <[email protected]>
The end-to-end editor tests embed real windows; without X11 dev headers they are skipped at configure time, and without a display they cannot run. Install libx11/xrandr/xext/xcursor + xvfb and run the test steps under xvfb-run on Linux. Co-Authored-By: Claude Fable 5 <[email protected]>
5afa08b to
02e4ebc
Compare
CustomUiWindow.hpp carried both platform implementations of its author window inline, guarded by a #if/#elif that made the file two editors in a trenchcoat and dragged <windows.h>/<X11/Xlib.h> (plus their macro-hygiene #undefs) into the middle of every plug-in TU that includes it. Hide the window behind a forward-declared pimpl: the header now declares only the avnd::gui_windowed_ui contract (open/close/idle/size) plus the message-bus endpoints the bindings introspect, and holds a std::unique_ptr<struct impl>. The two implementations move to sibling translation units, CustomUiWindow.win32.cpp (raw Win32 + GDI) and CustomUiWindow.x11.cpp (raw Xlib), each compiled into the plug-in modules by examples.cmake for its platform (and linking X11 there, as before). The header pulls in no windowing header at all -- exactly how a real toolkit editor would hide behind its own opaque handle. Behaviour is unchanged: the window class name, 360x120 size, gain gesture flow and message bus are identical. test_custom_ui_window still passes (clap module, live X display); vst3/vintage editor modules still build. Co-Authored-By: Claude Opus 4.8 (1M context) <[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.
The UI base layer on top of the backend fixes: concepts, host glue and the message bus — no bundled UI framework. After this PR, a plug-in can ship an editor written with any UI stack (Dear ImGui, Qt, JUCE, raw platform code…) and get it embedded, clocked and wired to automation in CLAP, VST2 and VST3 alike.
What's in
avnd/concepts/gui_window.hpp):avnd::gui_windowed_ui—T::ui::windowwithopen(gui_parent, gui_host)/close()/idle()/size();gui_hostis a fn-ptr automation-gesture protocol (flat param index, normalized [0,1], one begin/end per drag).binding/ui/editor.hpp): author window wins; a reference editor for declarative layouts only participates when a soft-UI backend is compiled in (AVND_SOFT_UI_EDITOR, PR 3) — this PR introduces the seam, not the backend.binding/ui/message_transport.hpp+serialization.hpp):ui::bus/ Tier Csend_message/process_messageendpoints over lock-free moodycamel queues (audio thread never allocates or blocks); pfr-based serializer for string/vector/aggregate payloads.clap.gui+clap.timer-support; VST2EditOpen/EditClose/EditIdle/EditGetRect+ audioMaster gestures; VST3IPlugViewwithIPlugViewContentScaleSupport, per-platform UI tick (SetTimer / hostIRunLoop/ CFRunLoopTimer) and the IMessage bus across the component/controller split (UI-thread-only IMessage allocation, seebinding/vst3/bus.hpp).examples/Advanced/UI/CustomUiWindow.hpp— a gain whose editor is raw Win32/GDI on Windows and raw Xlib on Linux, no library;tests/ui/test_custom_ui_window.cppembeds it in a real window, injects a drag, and asserts gestures + bus round-trip (passes on X11 with no soft stack present — the layering is real).Validation
Part 2/3; stacks on #160, and #162 (the bundled Nuklear/pugl/canvas_ity editor) builds on this.
🤖 Generated with Claude Code