diff --git a/CHANGELOG.md b/CHANGELOG.md index ad7bfed0..b0126faf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ - On Windows, fix `Window::set_visible` not setting internal flags correctly. This resulted in some weird behavior. - Add `DeviceEvent::ModifiersChanged`. - Deprecate `modifiers` fields in other events in favor of `ModifiersChanged`. +- On X11, `WINIT_HIDPI_FACTOR` now dominates `Xft.dpi` when picking DPI factor for output. +- On X11, add special value `randr` for `WINIT_HIDPI_FACTOR` to make winit use self computed DPI factor instead of the one from `Xft.dpi`. # 0.20.0 Alpha 5 (2019-12-09) diff --git a/src/platform_impl/linux/x11/util/randr.rs b/src/platform_impl/linux/x11/util/randr.rs index 28fcb601..4630389e 100644 --- a/src/platform_impl/linux/x11/util/randr.rs +++ b/src/platform_impl/linux/x11/util/randr.rs @@ -6,24 +6,17 @@ use super::{ }; use crate::{dpi::validate_hidpi_factor, platform_impl::platform::x11::VideoMode}; +/// Represents values of `WINIT_HIDPI_FACTOR`. +pub enum EnvVarDPI { + Randr, + Scale(f64), + NotSet, +} + pub fn calc_dpi_factor( (width_px, height_px): (u32, u32), (width_mm, height_mm): (u64, u64), ) -> f64 { - // Override DPI if `WINIT_HIDPI_FACTOR` variable is set - let dpi_override = env::var("WINIT_HIDPI_FACTOR") - .ok() - .and_then(|var| f64::from_str(&var).ok()); - if let Some(dpi_override) = dpi_override { - if !validate_hidpi_factor(dpi_override) { - panic!( - "`WINIT_HIDPI_FACTOR` invalid; DPI factors must be normal floats greater than 0. Got `{}`", - dpi_override, - ); - } - return dpi_override; - } - // See http://xpra.org/trac/ticket/728 for more information. if width_mm == 0 || height_mm == 0 { warn!("XRandR reported that the display's 0mm in size, which is certifiably insane"); @@ -107,16 +100,55 @@ impl XConnection { (*output_info).nameLen as usize, ); let name = String::from_utf8_lossy(name_slice).into(); - let hidpi_factor = if let Some(dpi) = self.get_xft_dpi() { - dpi / 96. - } else { - calc_dpi_factor( + // Override DPI if `WINIT_HIDPI_FACTOR` variable is set + let dpi_env = env::var("WINIT_HIDPI_FACTOR").ok().map_or_else( + || EnvVarDPI::NotSet, + |var| { + if var.to_lowercase() == "randr" { + EnvVarDPI::Randr + } else if let Ok(dpi) = f64::from_str(&var) { + EnvVarDPI::Scale(dpi) + } else if var.is_empty() { + EnvVarDPI::NotSet + } else { + panic!( + "`WINIT_HIDPI_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{}`", + var + ); + } + }, + ); + + let hidpi_factor = match dpi_env { + EnvVarDPI::Randr => calc_dpi_factor( ((*crtc).width as u32, (*crtc).height as u32), ( (*output_info).mm_width as u64, (*output_info).mm_height as u64, ), - ) + ), + EnvVarDPI::Scale(dpi_override) => { + if !validate_hidpi_factor(dpi_override) { + panic!( + "`WINIT_HIDPI_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{}`", + dpi_override, + ); + } + dpi_override + } + EnvVarDPI::NotSet => { + if let Some(dpi) = self.get_xft_dpi() { + dpi / 96. + } else { + calc_dpi_factor( + ((*crtc).width as u32, (*crtc).height as u32), + ( + (*output_info).mm_width as u64, + (*output_info).mm_height as u64, + ), + ) + } + } }; (self.xrandr.XRRFreeOutputInfo)(output_info);