From 1e5e157c25df741734ef1a59f37095bebed470a4 Mon Sep 17 00:00:00 2001 From: unohee Date: Tue, 15 Sep 2026 22:32:31 +0900 Subject: [PATCH] fix(egui): let synchronous hosts read the pending resize (AUD-1611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The frame flow consumed requested_size with swap(None) *before* calling context.request_resize(). Synchronous hosts read Editor::size() inside that call, so standalone (GuiTask::Resize) and CLAP (host_gui->request_resize) received the *previous* size: the egui surface scaled immediately while the OS window was resized one interaction behind — the reported macOS standalone symptom (skin shrinks, window stays; growing shrinks the window). Peek requested_size first, call the host while the pending value is still observable, and only then consume it. Hosts that read asynchronously (VST3 IPlugFrame via a posted task) are unaffected — they already read after size.store(). When the host refuses (AUv2 has no resize API) the request is dropped as before instead of retrying every frame. Verified by instrumentation on the macOS standalone: with the fix, each queued GuiTask::Resize carries the requested size (previously it carried the stored one). --- nih_plug_egui/src/editor.rs | 63 ++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/nih_plug_egui/src/editor.rs b/nih_plug_egui/src/editor.rs index ffdcfba89..9acfee959 100644 --- a/nih_plug_egui/src/editor.rs +++ b/nih_plug_egui/src/editor.rs @@ -118,33 +118,46 @@ where warmup_frames = warmup_frames.saturating_sub(1); // If the window was requested to resize - if let Some(new_size) = egui_state.requested_size.swap(None) { + if egui_state.requested_size.load().is_some() { // Ask the plugin host to resize to self.size() if context.request_resize() { - // new_size 는 논리 픽셀. baseview window.resize() 와 - // egui screen_rect 둘 다 갱신해야 한다. - // - // macOS standalone 에서는 NSWindow::setContentSize_ 로 OS 창은 - // 커지지만 WindowEvent::Resized 가 backing-property 변경 때만 - // 발생해 egui 의 physical_size/screen_rect 가 갱신되지 않는다 - // (커진 창의 좌상단 옛 크기 영역에만 GUI, 나머지 빈 배경). - // - // 그래서 queue.resize(PhySize) 로 egui 의 physical_size 를 - // 직접 갱신한다. physical_size 는 물리 픽셀이므로 DPI 배율을 - // 곱한다. ViewportCommand::InnerSize(논리) 는 baseview 의 - // window.resize() 를 호출해 OS 창 자체를 리사이즈한다. - let ppp = egui_ctx.pixels_per_point(); - queue.resize(PhySize::new( - (new_size.0 as f32 * ppp).round() as u32, - (new_size.1 as f32 * ppp).round() as u32, - )); - egui_ctx.send_viewport_cmd(ViewportCommand::InnerSize(Vec2::new( - new_size.0 as f32, - new_size.1 as f32, - ))); - - // Update the state - egui_state.size.store(new_size); + // Consume the request *after* the host call. Synchronous + // hosts (standalone, CLAP) read `Editor::size()` inside + // `request_resize()`, so the pending value must still be + // present then. Swapping first made them observe the + // previous size: the egui surface scaled immediately but + // the OS window was resized to the *previous* request, + // lagging one interaction behind (AUD-1611). + if let Some(new_size) = egui_state.requested_size.swap(None) { + // new_size 는 논리 픽셀. baseview window.resize() 와 + // egui screen_rect 둘 다 갱신해야 한다. + // + // macOS standalone 에서는 NSWindow::setContentSize_ 로 OS 창은 + // 커지지만 WindowEvent::Resized 가 backing-property 변경 때만 + // 발생해 egui 의 physical_size/screen_rect 가 갱신되지 않는다 + // (커진 창의 좌상단 옛 크기 영역에만 GUI, 나머지 빈 배경). + // + // 그래서 queue.resize(PhySize) 로 egui 의 physical_size 를 + // 직접 갱신한다. physical_size 는 물리 픽셀이므로 DPI 배율을 + // 곱한다. ViewportCommand::InnerSize(논리) 는 baseview 의 + // window.resize() 를 호출해 OS 창 자체를 리사이즈한다. + let ppp = egui_ctx.pixels_per_point(); + queue.resize(PhySize::new( + (new_size.0 as f32 * ppp).round() as u32, + (new_size.1 as f32 * ppp).round() as u32, + )); + egui_ctx.send_viewport_cmd(ViewportCommand::InnerSize(Vec2::new( + new_size.0 as f32, + new_size.1 as f32, + ))); + + // Update the state + egui_state.size.store(new_size); + } + } else { + // The host cannot resize (AUv2 has no resize API). Drop + // the request instead of retrying it every frame. + egui_state.requested_size.store(None); } }