diff --git a/examples/plugin_clack/src/gui.rs b/examples/plugin_clack/src/gui.rs index 0d4beb44..0aef8bee 100644 --- a/examples/plugin_clack/src/gui.rs +++ b/examples/plugin_clack/src/gui.rs @@ -72,7 +72,13 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> { let Some(gui) = self.borrow_window() else { return Err(PluginError::Message("set_scale called without a GUI active")); }; - gui.suggest_fallback_scale_factor(scale)?; + // An error tells the host the scale was ignored (clap_plugin_gui::set_scale returns + // false), so it takes the size from get_size rather than assume its own scale. + if !gui.suggest_fallback_scale_factor(scale)? { + return Err(PluginError::Message( + "set_scale ignored: the platform provides its own scale factor", + )); + } Ok(()) } diff --git a/examples/plugin_clack_femtovg/src/gui.rs b/examples/plugin_clack_femtovg/src/gui.rs index cdfd5711..3a32bbb1 100644 --- a/examples/plugin_clack_femtovg/src/gui.rs +++ b/examples/plugin_clack_femtovg/src/gui.rs @@ -59,7 +59,13 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> { let Some(gui) = self.borrow_window() else { return Err(PluginError::Message("set_scale called without a GUI active")); }; - gui.suggest_fallback_scale_factor(scale)?; + // An error tells the host the scale was ignored (clap_plugin_gui::set_scale returns + // false), so it takes the size from get_size rather than assume its own scale. + if !gui.suggest_fallback_scale_factor(scale)? { + return Err(PluginError::Message( + "set_scale ignored: the platform provides its own scale factor", + )); + } Ok(()) } diff --git a/host/src/window.rs b/host/src/window.rs index 94d665ab..ce784ea9 100644 --- a/host/src/window.rs +++ b/host/src/window.rs @@ -61,14 +61,19 @@ pub trait HostedWindow { /// If the given fallback scale factor is actually useful and different from the current one /// (1.0 by default), this will resize and redraw the window accordingly. /// + /// Returns `true` if the given scale factor is now the one the window uses, and `false` if it + /// was ignored because the platform provides its own. Plugins can pass this on to the host: + /// CLAP's `clap_plugin_gui::set_scale` returns `false` when the call was ignored, which tells + /// the host to take the size from `get_size` rather than assume its own scale. + /// /// # Platform compatibility notes. /// /// On Win32, this value is used if running on early versions of Windows 10 (or earlier). /// /// On X11, this value is used if no `Xft.dpi`setting is set. /// - /// On macOS, this function is always a no-op. - fn suggest_fallback_scale_factor(&self, scale_factor: f64) -> Result<(), Box>; + /// On macOS, this function is always a no-op, and always returns `false`. + fn suggest_fallback_scale_factor(&self, scale_factor: f64) -> Result>; /// Closes and destroys the window. /// diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index 79f447da..05c59a31 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -119,9 +119,9 @@ impl WindowHandle { Ok(()) } - pub fn suggest_scale_factor(&self, _scale_factor: f64) -> Result<()> { + pub fn suggest_scale_factor(&self, _scale_factor: f64) -> Result { // This does not do anything on macOS: all coordinates are already logical - Ok(()) + Ok(false) } pub fn set_parent(&self, new_parent: ParentWindowHandle) -> Result<()> { diff --git a/src/platform/win/window.rs b/src/platform/win/window.rs index fc9156cc..56d2bebe 100644 --- a/src/platform/win/window.rs +++ b/src/platform/win/window.rs @@ -91,7 +91,9 @@ impl WindowHandle { #[inline(always)] pub fn host_timer_callback(&self, _: crate::host::TimerId) {} - pub fn suggest_scale_factor(&self, new_host_scale_factor: f64) -> Result<()> { + /// Returns whether the suggested scale factor is now the one in use (`false` when the OS + /// provides per-monitor scaling itself). + pub fn suggest_scale_factor(&self, new_host_scale_factor: f64) -> Result { let new_dpi = Dpi::from_scale_factor(new_host_scale_factor) .ok_or(PlatformError::InvalidScaleFactor)?; @@ -101,12 +103,12 @@ impl WindowHandle { let dpi_scaling_strategy = self.state.dpi_scaling_strategy.get(); if !dpi_scaling_strategy.should_use_host_suggested_scale_factor { - return Ok(()); + return Ok(false); } self.state.current_dpi.set(new_dpi); - let Some(hwnd) = self.hwnd.get() else { return Ok(()) }; + let Some(hwnd) = self.hwnd.get() else { return Ok(true) }; let current_size = self.state.current_size.get(); let new_size = self @@ -118,7 +120,7 @@ impl WindowHandle { // This call doesn't meaningfully change the scaling factor, ignore the result if current_size == new_size { - return Ok(()); + return Ok(true); } let _guard = self.state.originate_host_resize(); @@ -127,7 +129,7 @@ impl WindowHandle { hwnd.resize_and_activate(new_size, new_dpi, &dpi_ctx)?; if self.state.current_size.get() == new_size { - Ok(()) + Ok(true) } else { Err(PlatformError::UnexpectedResizeResult { new_actual_size: self.state.current_size.get(), diff --git a/src/platform/x11/event_loop.rs b/src/platform/x11/event_loop.rs index 81e849c5..31ede242 100644 --- a/src/platform/x11/event_loop.rs +++ b/src/platform/x11/event_loop.rs @@ -179,7 +179,7 @@ impl EventLoop { self.sizing_state.handle_host_resize(new_size, &self.handler, &self.shared) } - pub fn suggest_scale_factor(&self, scale: f64) -> PlatformResult<()> { + pub fn suggest_scale_factor(&self, scale: f64) -> PlatformResult { self.sizing_state.handle_host_suggest_scale_factor(scale, &self.handler, &self.shared) } diff --git a/src/platform/x11/sizing.rs b/src/platform/x11/sizing.rs index 926edab9..9df1b3d1 100644 --- a/src/platform/x11/sizing.rs +++ b/src/platform/x11/sizing.rs @@ -106,20 +106,23 @@ impl SizingState { shared.sizing_state.resize_from_host(new_size, handler, shared) } + /// Returns whether the suggested scale factor is now the one in use (`false` if the system + /// provides its own, which takes precedence). pub fn handle_host_suggest_scale_factor( &self, scale: f64, handler: &Handler, shared: &WindowShared, - ) -> Result<(), PlatformError> { + ) -> Result { shared.sizing_state.host_suggested_scale_factor.set(Some(scale)); // If the scaling factor is already provided by the system, do nothing if shared.sizing_state.system_scale_factor.get().is_some() { - return Ok(()); + return Ok(false); }; let current_logical_size = shared.sizing_state.size().to_logical::(1.0); let new_physical_size = current_logical_size.to_physical(scale); - shared.sizing_state.resize_from_host(new_physical_size, handler, shared) + shared.sizing_state.resize_from_host(new_physical_size, handler, shared)?; + Ok(true) } } diff --git a/src/platform/x11/window_handle.rs b/src/platform/x11/window_handle.rs index 8cabda34..eabb0ef0 100644 --- a/src/platform/x11/window_handle.rs +++ b/src/platform/x11/window_handle.rs @@ -22,7 +22,8 @@ impl WindowHandle { self.handle_evloop(|e| e.resize(new_size)) } - pub fn suggest_scale_factor(&self, scale: f64) -> PlatformResult<()> { + /// Returns whether the suggested scale factor is now the one in use. + pub fn suggest_scale_factor(&self, scale: f64) -> PlatformResult { self.handle_evloop(|e| e.suggest_scale_factor(scale)) } @@ -87,10 +88,12 @@ impl WindowHandle { } impl WindowHandle { - fn handle_evloop( - &self, handler: impl FnOnce(&EventLoop) -> PlatformResult<()>, - ) -> PlatformResult<()> { - let Some(event_loop) = self.ev_loop.get() else { return Ok(()) }; + /// Runs `handler` on the event loop. Once the window is closed this does nothing, and returns + /// the default value (`()`, or `false`: a closed window has used nothing it was given). + fn handle_evloop( + &self, handler: impl FnOnce(&EventLoop) -> PlatformResult, + ) -> PlatformResult { + let Some(event_loop) = self.ev_loop.get() else { return Ok(T::default()) }; let res = handler(&event_loop); if self.shared.close_requested.get() { diff --git a/src/window.rs b/src/window.rs index 69bf836f..2737e42d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -103,17 +103,21 @@ impl Window { /// If the given fallback scale factor is actually useful and different from the current one /// (1.0 by default), this will resize and redraw the window accordingly. /// + /// Returns `true` if the given scale factor is now the one the window uses, and `false` if it + /// was ignored because the platform provides its own. Plugins can pass this on to the host: + /// CLAP's `clap_plugin_gui::set_scale` returns `false` when the call was ignored, which tells + /// the host to take the size from `get_size` rather than assume its own scale. + /// /// # Platform compatibility notes. /// /// On Win32, this value is used if running on early versions of Windows 10 (or earlier). /// /// On X11, this value is used if no `Xft.dpi`setting is set. /// - /// On macOS, this function is always a no-op. + /// On macOS, this function is always a no-op, and always returns `false`. #[inline] - pub fn suggest_fallback_scale_factor(&self, scale_factor: f64) -> Result<(), Error> { - self.inner.suggest_scale_factor(scale_factor)?; - Ok(()) + pub fn suggest_fallback_scale_factor(&self, scale_factor: f64) -> Result { + Ok(self.inner.suggest_scale_factor(scale_factor)?) } /// Closes and destroys the window. @@ -261,9 +265,8 @@ impl HostedWindow for Window { #[inline] fn suggest_fallback_scale_factor( &self, scale_factor: f64, - ) -> Result<(), Box> { - self.suggest_fallback_scale_factor(scale_factor)?; - Ok(()) + ) -> Result> { + Ok(self.suggest_fallback_scale_factor(scale_factor)?) } #[inline]