Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/render_wgpu/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ fn main() -> Result<(), baseview::Error> {
let window_open_options = WindowSettings::new()
.with_title("WGPU on Baseview")
.with_size(LogicalSize::new(512, 512))
.with_max_size(LogicalSize::new(512, 512));
.with_aspect_ratio(Some((1, 1)));

Window::create(window_open_options, |c| pollster::block_on(WgpuExample::new(c)))?
.run_until_closed()?;
Expand Down
7 changes: 7 additions & 0 deletions src/platform/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ impl BaseviewView {
let max_size = max_size.to_logical(scale_factor);
window.setContentMaxSize(NSSize::new(max_size.width, max_size.height));
}

if let Some(aspect_ratio) = this.state.sizing_strategy.aspect_ratio() {
window.setContentAspectRatio(NSSize::new(
aspect_ratio.numerator as _,
aspect_ratio.denominator as _,
))
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/platform/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ impl WindowHandle {
self.state.sizing_strategy.max_size()
}

pub fn aspect_ratio(&self) -> Option<AspectRatio> {
self.state.sizing_strategy.aspect_ratio()
}

#[inline]
pub fn handle_main_thread_callback(&self) {
// No-op
Expand Down
2 changes: 2 additions & 0 deletions src/platform/x11/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub enum PlatformError {
RequestFromMainThreadFailed(RequestFailed),
SendMainThread,
Redraw(String),
ResizeAttemptedOnFixedWindow,
#[cfg(feature = "opengl")]
XLib(crate::wrappers::xlib::XLibError),
#[cfg(feature = "opengl")]
Expand Down Expand Up @@ -96,6 +97,7 @@ impl Display for PlatformError {
PlatformError::Calloop(e) => e.fmt(f),
PlatformError::RequestFromMainThreadFailed(e) => e.fmt(f),
PlatformError::SendMainThread => FatalError::SendMainThread.fmt(f),
PlatformError::ResizeAttemptedOnFixedWindow => f.write_str("Attempted to resize a window which does not support resizing."),
#[cfg(feature = "opengl")]
PlatformError::XLib(e) => e.fmt(f),
#[cfg(feature = "opengl")]
Expand Down
50 changes: 29 additions & 21 deletions src/platform/x11/sizing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl SizingStateShared {
}

pub fn make_size_hints(&self) -> WmSizeHints {
get_size_hints(&self.sizing_strategy, self.window_size.get(), self.scale_factor())
get_size_hints(&self.sizing_strategy, self.scale_factor())
}

pub fn store_size(
Expand All @@ -198,13 +198,12 @@ impl SizingStateShared {
return Ok(());
}

window.resize(new_size)?.check()?;

if !self.sizing_strategy.is_resizable() {
let size_hints = get_size_hints(&self.sizing_strategy, new_size, self.scale_factor());
window.set_size_hints(size_hints)?.check()?;
return Err(PlatformError::ResizeAttemptedOnFixedWindow);
}

window.resize(new_size)?.check()?;

// This will trigger a `ConfigureNotify` event which will in turn change `self.window_info`
// and notify the window handler about it

Expand All @@ -220,6 +219,10 @@ impl SizingStateShared {
return Ok(());
};

if !self.sizing_strategy.is_resizable() {
return Err(PlatformError::ResizeAttemptedOnFixedWindow);
}

if let Err(()) =
handler.resize(WindowSize::from_physical(new_size.cast(), self.scale_factor()))
{
Expand All @@ -228,10 +231,6 @@ impl SizingStateShared {
}

shared.xcb_window.resize(new_size.cast())?.check()?; // Will not call handler, as size is the same as above.
if !self.sizing_strategy.is_resizable() {
let size_hints = get_size_hints(&self.sizing_strategy, new_size, self.scale_factor());
shared.xcb_window.set_size_hints(size_hints)?.check()?;
}

// These come from the Host, no need to notify it about the new size

Expand Down Expand Up @@ -290,28 +289,37 @@ impl SizingThreadShared {
}
}

pub fn get_size_hints(
strategy: &SizingStrategy, current_size: PhysicalSize<impl Pixel>, scale_factor: f64,
) -> WmSizeHints {
pub fn get_size_hints(strategy: &SizingStrategy, scale_factor: f64) -> WmSizeHints {
fn to_x11_aspect_ratio(aspect_ratio: crate::AspectRatio) -> x11rb::properties::AspectRatio {
match (aspect_ratio.numerator.try_into(), aspect_ratio.denominator.try_into()) {
(Ok(numerator), Ok(denominator)) => {
x11rb::properties::AspectRatio { numerator, denominator }
}
_ => x11rb::properties::AspectRatio {
numerator: (aspect_ratio.numerator as f64 / 2.0) as i32,
denominator: (aspect_ratio.denominator as f64 / 2.0) as i32,
},
}
}

let mut size_hints = WmSizeHints::default();

match strategy {
SizingStrategy::Fixed => {
size_hints.min_size = Some(to_size_hint(current_size));
SizingStrategy::Fixed { size } => {
size_hints.min_size = Some(to_size_hint(size.to_physical(scale_factor)));
size_hints.max_size = size_hints.min_size;
size_hints.aspect = None;
}
SizingStrategy::Resizable { min_size, max_size } => {
size_hints.min_size =
min_size.map(|s| to_size_hint(s.to_physical::<i32>(scale_factor)));
size_hints.max_size =
max_size.map(|s| to_size_hint(s.to_physical::<i32>(scale_factor)));
SizingStrategy::Resizable { min_size, max_size, aspect_ratio } => {
size_hints.min_size = min_size.map(|s| to_size_hint(s.to_physical(scale_factor)));
size_hints.max_size = max_size.map(|s| to_size_hint(s.to_physical(scale_factor)));
size_hints.aspect = aspect_ratio.map(to_x11_aspect_ratio).map(|a| (a, a))
}
}

size_hints
}

fn to_size_hint(size: PhysicalSize<impl Pixel>) -> (i32, i32) {
let size = size.cast();
fn to_size_hint(size: PhysicalSize<i32>) -> (i32, i32) {
(size.width, size.height)
}
6 changes: 5 additions & 1 deletion src/platform/x11/window_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::platform::x11::present::PresentThreadShared;
use crate::platform::x11::sizing::SizingThreadShared;
use crate::platform::x11::window_shared::WindowShared;
use crate::utils::SizingStrategy;
use crate::warn;
use crate::window::WindowInitializer;
use crate::{warn, AspectRatio};
use crate::{WindowContext, WindowSettings, WindowSize};
use calloop::LoopSignal;
use std::cell::{Cell, RefCell};
Expand Down Expand Up @@ -226,6 +226,10 @@ impl WindowThreadHandle {
self.sizing_strategy().max_size()
}

pub fn aspect_ratio(&self) -> Option<AspectRatio> {
self.sizing_strategy().aspect_ratio()
}

pub fn handle_main_thread_callback(&self) {
loop {
let Some(receiver) = self.callback_receiver.as_ref() else { return };
Expand Down
38 changes: 38 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub struct WindowSettings {
pub min_size: Option<Size>,
pub max_size: Option<Size>,

pub aspect_ratio: Option<AspectRatio>,

/// A fallback scale factor, if Baseview couldn't get one from the platform.
///
/// If the platform does already provide an accurate scaling factor, this doesn't do anything.
Expand Down Expand Up @@ -126,6 +128,12 @@ impl WindowSettings {
self
}

#[inline]
pub fn with_aspect_ratio<A: Into<AspectRatio>>(mut self, aspect_ratio: Option<A>) -> Self {
self.aspect_ratio = aspect_ratio.map(A::into);
self
}

/// Sets [`gl_config`](Self::gl_config) to the given value.
#[cfg(feature = "opengl")]
#[inline]
Expand All @@ -146,6 +154,7 @@ impl Default for WindowSettings {
resizable: true,
min_size: None,
max_size: None,
aspect_ratio: None,
#[cfg(feature = "opengl")]
gl_config: None,
}
Expand Down Expand Up @@ -193,3 +202,32 @@ impl From<platform::ParentWindowHandle> for ParentWindowHandle {
Self { inner }
}
}

/// An aspect ratio `numerator` / `denominator`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
/// The numerator of the aspect ratio.
pub numerator: u32,
/// The denominator of the aspect ratio.
pub denominator: u32,
}

impl AspectRatio {
/// Create a new aspect ratio with the given `numerator` and `denominator`.
#[inline]
pub fn new(numerator: u32, denominator: u32) -> Self {
Self { numerator, denominator }
}

#[inline]
pub fn ratio(&self) -> f64 {
(self.numerator as f64) / (self.denominator as f64)
}
}

impl From<(u32, u32)> for AspectRatio {
#[inline]
fn from((numerator, denominator): (u32, u32)) -> Self {
Self::new(numerator, denominator)
}
}
Loading
Loading