RustAudio / baseview

low-level window system interface for audio plugin UIs
Apache License 2.0
267 stars 57 forks source link

Support resizing windows after creation #136

Closed robbert-vdh closed 1 year ago

robbert-vdh commented 1 year ago

I've implemented this for Linux back in March, and I only just added Windows support. Still need to add macOS support, but I thought I'd submit a draft PR already because the changes needed for Windows support are pretty invasive. So we may want to discuss the best course of action first.

Resizing the window sends a WM_SIZE event and a couple other events to the window, so the window procedure and WindowState had to be changed to use interior mutability everywhere instead of wrapping the entire struct in a RefCell. This resolves most of the reentrant event call concerns from #130, but I'm not sure if it also prevents panics in that specific example To make this work there's now a deferred_tasks queue for handling tasks that are the result of a call to one of the Window methods in an event handler that may also indirectly emit other events. Perhaps Window::close() should also be implemented this way.

The Linux implementation was extremely straightforward, and I'll get to the macOS one next.

This closes #121.

robbert-vdh commented 1 year ago

So one thing I noticed is that the behavior for window resize notifications is different between the different platforms. On Windows the window handler would receive an event after the resize had successfully taken place, and on Linux this didn't happen. I changed the Linux implementation so it also does that.

On Windows and macOS the implementations also sent you duplicate Event::Window(WindowEvent::Resized(window_info)) events even if the new size is the same as the old one, so I changed the behaviors there to also only send the event if something changed.

robbert-vdh commented 1 year ago

So the Linux and Windows versions work great. The macOS version doesn't seem to resize the view at all (standalone windows are still resized, but the contents don't resize). Apple's docs on this are extremely sparse, so if anyone with more experience programming for their platform would like to chime in I'd appreciate it a lot!

robbert-vdh commented 1 year ago

Okay, everything should work great now. I'd appreciate it if others could give this a try as well! I've implemented support for this in my vizia fork which is used by nih_plug_vizia. All plugins in that repo that use Vizia will support resizing and you can also try running cargo run -p gain_gui_vizia --release.

robbert-vdh commented 1 year ago

Oh and something I have not yet done in this PR but that might improve perceived responsiveness is to draw a new frame as soon as the window resize event is received. Right now the .on_frame() call lags a bit behind the resize.

helgoboss commented 1 year ago

@robbert-vdh Thanks, the deferred_tasks queue is a good way to prevent the issue mentioned in #130, I just tested it! There's one small additional thing necessary to fix the issue: An API to let baseview consumers defer tasks, because the code in #130 which has reentrancy issues is not a part of the baseview crate itself. It's part of egui-baseview. I will make a PR.