Fix editor scaling/size issues on Windows#10
Conversation
- Add Window scale accessors to plugin editors and window adapters - Add new Window `screen_scale` functions, which can be used when the host queries the plugin's window size, and there's no window created yet
|
Thanks for your contribution! I actually didn't notice this on my Windows machine but it only has a scaling factor of 150%. I'll have to look through this quite carefully as scaling has been quite a headache to get consistenly working across platforms especially with all the corner cases such as drag & drop, resizeable windows etc. I'll check how this works with my commercial plugin using plugin-things and also check the situation in Linux. I'll then either comment on the PR or work on top of it. Again, thanks! |
|
Nothing to thank for! I'm happy that I can build stuff thanks to your work, which saves me the hassle of writing all that platform stuff by myself :) Yes, all this scaling stuff is a mess on Windows. Unfortunately, it won't get much better on Linux either. The only reliable way I'm aware of to get the scaling there in a portable way is using The most foolproof way to create a plugin GUI that works for everyone on Linux is to allow the user to set a custom scale in the plugin UI and just use a good guess as the default. Actually it would be neat if Either way, let me know if you would like me to provide any further feedback or assistance here with testing or finishing up this PR. |
| fn sceen_scale() -> f64 { | ||
| if let Some(main_thread_marker) = MainThreadMarker::new() { | ||
| if let Some(screen) = NSScreen::mainScreen(main_thread_marker) { | ||
| return screen.backingScaleFactor() | ||
| } | ||
| } | ||
| else { | ||
| #[cfg(debug_assertions)] | ||
| panic!("Calling screen_scale from an unexpected thread"); | ||
| } | ||
| 1.0 | ||
| } |
There was a problem hiding this comment.
How about to simplify this to:
| fn sceen_scale() -> f64 { | |
| if let Some(main_thread_marker) = MainThreadMarker::new() { | |
| if let Some(screen) = NSScreen::mainScreen(main_thread_marker) { | |
| return screen.backingScaleFactor() | |
| } | |
| } | |
| else { | |
| #[cfg(debug_assertions)] | |
| panic!("Calling screen_scale from an unexpected thread"); | |
| } | |
| 1.0 | |
| } | |
| fn screen_scale() -> f64 { | |
| let Some(main_thread_marker) = MainThreadMarker::new() else { | |
| debug_assert!(false, "Calling screen_scale from an unexpected thread"); | |
| return 1.0; | |
| }; | |
| NSScreen::mainScreen(main_thread_marker) | |
| .map_or(1.0, |screen| screen.backingScaleFactor()) | |
| } |
|
After giving this some thought, I'm not convinced this should be handled automatically in plugin-things. I've updated the gain example with the intended way of handling |
|
That surely would be an elegant way to avoid most of the ugly OS parts, but I can't make that work here. Using the updated gain example from the master branch on Windows:
If you go this way, then I think we definitely need a good default scaling (something like I though this should fix the above mentioned issue, but it's causing other problems on Windows: fn set_scale(&mut self, scale: f64) {
self.scale = scale;
if let Some(editor_handle) = self.editor_handle.as_ref() {
editor_handle.set_scale(scale);
}
}Maybe the window needs here needs to be resized as well then or the host must be notified of the window size? How did you solve those issues in your plugin? |
|
Ah yes, I forgot a crucial part in Curiously it still worked correctly in Bitwig and Live (not sure why you saw different behavior) but was wrong in Reaper. I don't have Renoise. Just committed a fix. |
|
Also: default scaling comes specifically from |
|
Yes, this works now in Live, Bitwig and Renoise now, but still doesn't work in hosts that don't set a scaling at all, e.g. Bidule. There may be others as well. Or what do you mean with "default scaling comes specifically from set_scale()"? This only relies on the host now, doesn't it? As mentioned previously, this could be resolved by initializing the editor's scale to match that of the default monitor. Initially using the "correct" scaling will also avoid an extra window resize here. |
|
My opinion is that this shouldn't be default behavior in the plugin framework since a correctly behaving host should call |
|
Okay. But scaling setters are optional for VST3 - not sure how Clap handles this. Scaling will work in most hosts now, so I guess that's good enough for a start! |
VST3 and Clap plugins currently open with wrong sizes (report a wrong size to the host) on systems with non-100% scaling settings. e.g. the window is half the size it should be on 4K monitors with a scaling of 200%:
Window::screen_scalehere, in case there's no window to query the size from yet, when the host asks for the plugin's window size before opening the plugin window.EditorHandle::scaleshould be used (was os_scale before), as windows on Windows may have different effectively applied scaling, depending on which monitor they are visible.The real fix is here:
Plus the impls for
EditorHandle::scaleandWindow::screen_scale.The rest tries making the
screen_scaleandscaleavailable toEditor. I'm not very familiar with the library, so there are likely easier and cleaner ways to do this. Please let me know if you can think of a better way of dealing with this.Ideally, the default impl of
Editorshould deal with all that stuff. Right now the fix assumes thatscaleis implemented correctly andcheck_window_sizeandset_window_sizeneed to adjust sizes for scaling manually too when implemented. But this is also outside the scope of this PR, at least for me, and likely requires a totally different Editor handling.Note: A similar fix may be necessary on Linux, but I haven't tested this yet, and also haven't implemented the Linux parts, so this only works for Windows. On macOS window sizes are logical sizes, so things should work as before here.
Also note that this doesn't address cases where scaling changes when a plugin window gets moved from one monitor to another with different DPI settings. The behavior of each host is different here so this is difficult to get right and should be addressed in a separate issue.