Skip to content

AUv2: initialize the Cocoa view before creating the plugin's GUI - #594

Merged
defiantnerd merged 1 commit into
nextfrom
auv2-view-init-before-gui-create
Oct 13, 2026
Merged

defiantnerd merged 1 commit into
nextfrom
auv2-view-init-before-gui-create

Conversation

@defiantnerd

Copy link
Copy Markdown
Collaborator

Fixes #582. An alternative to #591 — thanks @busticated for the report, the stack trace and the patch; this takes the first option you suggested in the issue.

What happens today

initWithAUv2: registers self as the CLAP window and runs gui->create() before [super initWithFrame:]. A plugin that calls request_resize from inside create() — which clap/ext/gui.h allows — therefore reaches -setFrame: on a view AppKit has not finished building, and NSView throws NSInternalInconsistencyException: '_trackingAreaHelper not allocated yet!'.

What this does

Initializes the view first, with the size the host offered, and creates the plugin's GUI into a view that is ready for it. A request_resize during create() then lands on the frame like any other resize, and the frame it leaves behind becomes the initial size; get_size() is only asked when create() did not ask for a size of its own, so the plugin's own request still wins.

canary moves to after _createWindow(). It says the view is connected to a live plugin GUI — which is what every other reader of it means (viewDidMoveToWindow, dealloc, -setFrame:, and _destroyWindow in wrapasauv2.cpp) — and it should not say so while create() is still running: the set_size() echo that -setFrame: normally hands back to the plugin would re-enter create(). That is the same reentrancy #591 avoids with its early return.

So no new state on the view: "may -setFrame: talk to the plugin yet" is canary, and "did create() ask for a size" is the frame having moved. Registering the window after [super initWithFrame:] also fixes a latent wrinkle — self and &canary were handed to the wrapper from an object super init had not returned yet.

Open question

Does the requested size really need to beat get_size()? After a request_resize in create(), a conforming plugin's get_size() should return the new size, in which case the NSEqualSizes branch can go and the fix is purely the reordering. @busticated — does nice-plug-egui's get_size() disagree with what it asked for? If it does, that reason should be written into the comment.

Testing

Builds all three AUv2 targets. Not yet verified in a host — auval cannot open an editor, so this wants the pluginval editor test from #582 and a look in Logic, where the host follows the view's frame-change notification.

initWithAUv2: registered self as the CLAP window and ran gui->create() before
[super initWithFrame:], so a plugin that called request_resize from inside
create() - which the GUI extension allows - reached -setFrame: on a view AppKit
had not finished building. NSView threw NSInternalInconsistencyException
("_trackingAreaHelper not allocated yet!") and the host aborted: GarageBand, and
pluginval's editor test (#582).

The view is now initialized first, with the size the host offered, and the
plugin's GUI is created into a view that is ready for it. A request_resize
during create() lands on the frame like any other resize, and the frame it
leaves behind becomes the initial size. get_size() is only asked when create()
did not ask for a size of its own, so the plugin's own request wins.

canary moves to after _createWindow(). It says the view is connected to a live
plugin GUI - which is what every other reader of it means - and it should not
say so while create() is still running: the set_size() echo that -setFrame:
normally hands back to the plugin would re-enter create().

Registering the window after [super initWithFrame:] is also the ordering the
registration wanted anyway: self and &canary were handed to the wrapper from an
object that super init had not returned yet.
@busticated

Copy link
Copy Markdown

ah, yeah that's much nicer - thanks 🙏👍

confirmed this fixes #582 for me.

here's how i repro'ed things: a nice-plug@0.4.2 / nice-plug-egui@0.5.1 plugin built through clap-wrapper-rs (repo), pluginval@1.0.4 (strictness 5 | repo).

  • stock v0.16.0 aborts in the AU editor test right after creating NSView
  • v0.16.0 with this commit passes clap-validator@0.4.1, pluginval (VST3 and AU) and auval.

NOTE: I applied the commit to v0.16.0 by hand, leaving out the #536 entry guard, which isn't in that release.

i'll close #591 in favor of this. thanks again for working on this stuff.

@defiantnerd
defiantnerd merged commit 6b67a62 into next Oct 13, 2026
28 checks passed
@defiantnerd
defiantnerd deleted the auv2-view-init-before-gui-create branch October 13, 2026 10:19
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