Better DPI scale factor strategy for X11
This commit is contained in:
parent
16363dcc4b
commit
c42b218bb1
|
@ -15,6 +15,7 @@ gl = "0.14.0"
|
||||||
[target.'cfg(target_os="linux")'.dependencies]
|
[target.'cfg(target_os="linux")'.dependencies]
|
||||||
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
|
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
|
||||||
x11 = { version = "2.3", features = ["xlib", "glx"]}
|
x11 = { version = "2.3", features = ["xlib", "glx"]}
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os="windows")'.dependencies]
|
[target.'cfg(target_os="windows")'.dependencies]
|
||||||
winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi", "wingdi"] }
|
winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi", "wingdi"] }
|
||||||
|
|
15
README.md
15
README.md
|
@ -8,9 +8,12 @@ A low-level windowing system geared towards making audio plugin UIs.
|
||||||
|
|
||||||
Below is a proposed list of milestones (roughly in-order) and their status. Subject to change at any time.
|
Below is a proposed list of milestones (roughly in-order) and their status. Subject to change at any time.
|
||||||
|
|
||||||
| Feature | Windows | Mac OS | Linux |
|
| Feature | Windows | Mac OS | Linux |
|
||||||
| -------------------------------------- | ------------------ | ------------------ | ------------------ |
|
| ----------------------------------------------- | ------------------ | ------------------ | ------------------ |
|
||||||
| Spawns a window, no parent | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
| Spawns a window, no parent | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||||
| Cross-platform API for window spawning | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
| Cross-platform API for window spawning | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||||
| Window uses an OpenGL surface | :heavy_check_mark: | | :heavy_check_mark: |
|
| Window uses an OpenGL surface | :heavy_check_mark: | | :heavy_check_mark: |
|
||||||
| Basic DPI scaling support | | | :question: |
|
| Can find DPI scale factor | | | :heavy_check_mark: |
|
||||||
|
| Basic event handling (mouse, keyboard) | | | |
|
||||||
|
| Parent window support | | | |
|
||||||
|
| *(Converge on a common API for all platforms?)* | | | |
|
||||||
|
|
|
@ -19,6 +19,7 @@ use crate::WindowOpenOptions;
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
xcb_connection: XcbConnection,
|
xcb_connection: XcbConnection,
|
||||||
|
scaling: Option<f64>, // DPI scale, 96.0 is "default".
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
@ -229,8 +230,15 @@ impl Window {
|
||||||
xlib::XSync(xcb_connection.conn.get_raw_dpy(), xlib::False);
|
xlib::XSync(xcb_connection.conn.get_raw_dpy(), xlib::False);
|
||||||
}
|
}
|
||||||
|
|
||||||
let x11_window = Self { xcb_connection };
|
let mut x11_window = Self {
|
||||||
|
xcb_connection,
|
||||||
|
scaling: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
x11_window.scaling = x11_window
|
||||||
|
.get_scaling_xft()
|
||||||
|
.or(x11_window.get_scaling_screen_dimensions());
|
||||||
|
println!("Scale factor: {:?}", x11_window.scaling);
|
||||||
x11_window.handle_events(window_id, ctx);
|
x11_window.handle_events(window_id, ctx);
|
||||||
|
|
||||||
return x11_window;
|
return x11_window;
|
||||||
|
@ -259,34 +267,83 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Try to get the scaling with this function first.
|
||||||
// Figure out the DPI scaling by opening a new temporary connection and asking XCB
|
// If this gives you `None`, fall back to `get_scaling_screen_dimensions`.
|
||||||
// TODO: currently returning (96, 96) on my system, even though I have 4k screens. Problem with my setup perhaps?
|
// If neither work, I guess just assume 96.0 and don't do any scaling.
|
||||||
#[allow(dead_code)]
|
fn get_scaling_xft(&self) -> Option<f64> {
|
||||||
pub fn get_scaling() -> (u32, u32) {
|
use std::ffi::CString;
|
||||||
// Connect to the X server
|
use x11::xlib::{
|
||||||
let xcb_connection = XcbConnection::new();
|
XResourceManagerString, XrmDestroyDatabase, XrmGetResource, XrmGetStringDatabase,
|
||||||
|
XrmValue,
|
||||||
// Figure out screen information
|
};
|
||||||
let setup = xcb_connection.conn.get_setup();
|
|
||||||
let screen = setup
|
let display = self.xcb_connection.conn.get_raw_dpy();
|
||||||
.roots()
|
unsafe {
|
||||||
.nth(xcb_connection.xlib_display as usize)
|
let rms = XResourceManagerString(display);
|
||||||
.unwrap();
|
if !rms.is_null() {
|
||||||
|
let db = XrmGetStringDatabase(rms);
|
||||||
// Get the DPI from the screen struct
|
if !db.is_null() {
|
||||||
//
|
let mut value = XrmValue {
|
||||||
// there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
|
size: 0,
|
||||||
// dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
|
addr: std::ptr::null_mut(),
|
||||||
// = N pixels / (M inch / 25.4)
|
};
|
||||||
// = N * 25.4 pixels / M inch
|
|
||||||
let width_px = screen.width_in_pixels() as f64;
|
let mut value_type: *mut libc::c_char = std::ptr::null_mut();
|
||||||
let width_mm = screen.width_in_millimeters() as f64;
|
let name_c_str = CString::new("Xft.dpi").unwrap();
|
||||||
let height_px = screen.height_in_pixels() as f64;
|
let c_str = CString::new("Xft.Dpi").unwrap();
|
||||||
let height_mm = screen.height_in_millimeters() as f64;
|
|
||||||
let xres = width_px * 25.4 / width_mm;
|
let dpi = if XrmGetResource(
|
||||||
let yres = height_px * 25.4 / height_mm;
|
db,
|
||||||
|
name_c_str.as_ptr(),
|
||||||
((xres + 0.5) as u32, (yres + 0.5) as u32)
|
c_str.as_ptr(),
|
||||||
|
&mut value_type,
|
||||||
|
&mut value,
|
||||||
|
) != 0
|
||||||
|
&& !value.addr.is_null()
|
||||||
|
{
|
||||||
|
let value_addr: &CStr = CStr::from_ptr(value.addr);
|
||||||
|
value_addr.to_str().ok();
|
||||||
|
let value_str = value_addr.to_str().ok()?;
|
||||||
|
let value_f64 = value_str.parse().ok()?;
|
||||||
|
Some(value_f64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
XrmDestroyDatabase(db);
|
||||||
|
|
||||||
|
return dpi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get the scaling with `get_scaling_xft` first.
|
||||||
|
// Only use this function as a fallback.
|
||||||
|
// If neither work, I guess just assume 96.0 and don't do any scaling.
|
||||||
|
fn get_scaling_screen_dimensions(&self) -> Option<f64> {
|
||||||
|
// Figure out screen information
|
||||||
|
let setup = self.xcb_connection.conn.get_setup();
|
||||||
|
let screen = setup
|
||||||
|
.roots()
|
||||||
|
.nth(self.xcb_connection.xlib_display as usize)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Get the DPI from the screen struct
|
||||||
|
//
|
||||||
|
// there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
|
||||||
|
// dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
|
||||||
|
// = N pixels / (M inch / 25.4)
|
||||||
|
// = N * 25.4 pixels / M inch
|
||||||
|
let width_px = screen.width_in_pixels() as f64;
|
||||||
|
let width_mm = screen.width_in_millimeters() as f64;
|
||||||
|
let height_px = screen.height_in_pixels() as f64;
|
||||||
|
let height_mm = screen.height_in_millimeters() as f64;
|
||||||
|
let _xres = width_px * 25.4 / width_mm;
|
||||||
|
let yres = height_px * 25.4 / height_mm;
|
||||||
|
|
||||||
|
// TODO: choose between `xres` and `yres`? (probably both are the same?)
|
||||||
|
Some(yres)
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue