Skip to content

CLAP: support host-driven GUI resizing (Editor::set_size + ViziaState::new_resizable)#273

Open
chrisredekop wants to merge 2 commits into
robbert-vdh:masterfrom
chrisredekop:feature/clap-host-resize
Open

CLAP: support host-driven GUI resizing (Editor::set_size + ViziaState::new_resizable)#273
chrisredekop wants to merge 2 commits into
robbert-vdh:masterfrom
chrisredekop:feature/clap-host-resize

Conversation

@chrisredekop

Copy link
Copy Markdown

What

Some CLAP hosts resize plugin windows host-side: the user drags the host's window frame and the host negotiates through adjust_size()/set_size(). FL Studio works exclusively this way. The CLAP wrapper previously rejected every proposal (and hardcoded can_resize -> false), which makes nih-plug plugin windows completely rigid there.

This PR adds opt-in support for that model, addressing the "TODO: Implement Host->Plugin GUI resizing" in the CLAP wrapper:

  • Editor::set_size(width, height) (logical pixels, same units as size()), default implementation rejects — existing editors keep their exact fixed-size behavior.
  • CLAP wrapper: ext_gui_can_resize returns true, ext_gui_adjust_size echoes the host's proposal, ext_gui_set_size forwards to Editor::set_size and falls back to the old only-the-current-size comparison when the editor does not implement it.
  • nih_plug_vizia: ViziaState::new_resizable(size_fn, on_host_resize) opts an editor in. The callback updates (and may clamp) whatever state size_fn reads; the new size is applied to the embedded window on the GUI thread via an ApplyHostResize message through vizia's event proxy. The proxy is used because vizia_baseview only runs the idle callback on input events — and a host frame drag generates none. The GeometryChanged that follows skips the request_resize renegotiation through a one-shot flag, since hosts that refuse plugin-initiated requests (FL) would otherwise revert their own resize.

Existing ViziaState::new/new_with_default_scale_factor editors are unaffected (on_host_resize: Noneset_size rejects, legacy behavior).

Verified

Tested in FL Studio 2025 (Windows 11, 125 % DPI): dragging FL's frame grip resizes window and content live and smoothly; plugin-side clamping works; sizes persist via the plugin's own #[persist] state. clap-validator 0.3.2 passes (in-process).

Heads-up for Windows

The embedded window relayout additionally needs a baseview rev that includes current master's Win32 resize handling. The rev pinned today (2c1b1a7) pre-writes the new size into window_info, so the WM_SIZE that follows SetWindowPos compares equal and the Resized event is swallowed — the HWND resizes but vizia never relays out. baseview master has this fixed (send_resized refactor), so a baseview pin bump makes this work end-to-end; we currently carry a one-line baseview patch alongside this branch.

Happy to adjust naming/placement — set_size mirroring size() units felt most consistent, but an explicit physical/logical split would work too.

Some CLAP hosts resize plugin windows host-side: the user drags the
hosts window frame and the host negotiates through adjust_size() /
set_size() (FL Studio works exclusively this way). The wrapper
previously rejected every proposal, which made plugin windows
completely rigid there, and can_resize was hardcoded to false so
plugin-initiated request_resize() calls were ignored too.

- Editor gains set_size(width, height) (logical pixels, same units as
  size()) with a default implementation that rejects the resize, so
  existing editors keep their fixed-size behavior.
- ext_gui_can_resize returns true, ext_gui_adjust_size echoes the
  hosts proposal, and ext_gui_set_size forwards it to the editor,
  falling back to the old only-the-current-size check for editors
  that do not implement set_size.
ViziaState::new_resizable(size_fn, on_host_resize) opts an editor into
host-driven resizing: Editor::set_size converts the proposal into
size_fn units, the apps callback updates (and may clamp) whatever
state size_fn reads, and an ApplyHostResize message is emitted through
vizias event proxy so the embedded window is resized on the GUI
thread. The proxy is used rather than the idle callback because
vizia_baseview only runs on_idle on input events, and a host frame
drag generates none (the idle path stays as a fallback).

The GeometryChanged that follows a host-driven resize skips the
request_resize renegotiation via a one-shot flag: the host already
approved that size, and hosts that refuse plugin-initiated requests
would otherwise revert their own resize.

Note for Windows: the embedded window relayout additionally needs a
baseview rev that includes the current masters Win32 resize handling.
The rev currently pinned by nih-plug (2c1b1a7) pre-writes the new size
into its bookkeeping, which makes the WM_SIZE following SetWindowPos
look like a no-op and swallows the Resized event; baseview master has
this fixed.
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.

1 participant