Implement X11 extensions using x11rb instead of Xlib
Removes Xlib code by replacing it with the x11rb equivalent, the commit handles xrandr, xinput, xinput2, and xkb. Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
parent
0c8cf94a70
commit
bb9b629bc3
10 changed files with 399 additions and 394 deletions
|
|
@ -1,12 +1,11 @@
|
|||
use std::{env, slice, str::FromStr};
|
||||
use std::{env, str, str::FromStr};
|
||||
|
||||
use super::{
|
||||
ffi::{CurrentTime, RRCrtc, RRMode, Success, XRRCrtcInfo, XRRScreenResources},
|
||||
*,
|
||||
};
|
||||
use super::*;
|
||||
use crate::platform_impl::platform::x11::monitor;
|
||||
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoMode};
|
||||
|
||||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||
|
||||
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
||||
pub enum EnvVarDPI {
|
||||
Randr,
|
||||
|
|
@ -37,42 +36,32 @@ pub fn calc_dpi_factor(
|
|||
|
||||
impl XConnection {
|
||||
// Retrieve DPI from Xft.dpi property
|
||||
pub unsafe fn get_xft_dpi(&self) -> Option<f64> {
|
||||
(self.xlib.XrmInitialize)();
|
||||
let resource_manager_str = (self.xlib.XResourceManagerString)(self.display);
|
||||
if resource_manager_str.is_null() {
|
||||
return None;
|
||||
}
|
||||
if let Ok(res) = ::std::ffi::CStr::from_ptr(resource_manager_str).to_str() {
|
||||
let name: &str = "Xft.dpi:\t";
|
||||
for pair in res.split('\n') {
|
||||
if let Some(stripped) = pair.strip_prefix(name) {
|
||||
return f64::from_str(stripped).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
pub fn get_xft_dpi(&self) -> Option<f64> {
|
||||
self.database()
|
||||
.get_string("Xfi.dpi", "")
|
||||
.and_then(|s| f64::from_str(s).ok())
|
||||
}
|
||||
pub unsafe fn get_output_info(
|
||||
pub fn get_output_info(
|
||||
&self,
|
||||
resources: *mut XRRScreenResources,
|
||||
crtc: *mut XRRCrtcInfo,
|
||||
resources: &monitor::ScreenResources,
|
||||
crtc: &randr::GetCrtcInfoReply,
|
||||
) -> Option<(String, f64, Vec<VideoMode>)> {
|
||||
let output_info =
|
||||
(self.xrandr.XRRGetOutputInfo)(self.display, resources, *(*crtc).outputs.offset(0));
|
||||
if output_info.is_null() {
|
||||
// When calling `XRRGetOutputInfo` on a virtual monitor (versus a physical display)
|
||||
// it's possible for it to return null.
|
||||
// https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=816596
|
||||
let _ = self.check_errors(); // discard `BadRROutput` error
|
||||
return None;
|
||||
}
|
||||
let output_info = match self
|
||||
.xcb_connection()
|
||||
.randr_get_output_info(crtc.outputs[0], x11rb::CURRENT_TIME)
|
||||
.map_err(X11Error::from)
|
||||
.and_then(|r| r.reply().map_err(X11Error::from))
|
||||
{
|
||||
Ok(output_info) => output_info,
|
||||
Err(err) => {
|
||||
warn!("Failed to get output info: {:?}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let bit_depth = self.default_root().root_depth;
|
||||
|
||||
let output_modes =
|
||||
slice::from_raw_parts((*output_info).modes, (*output_info).nmode as usize);
|
||||
let resource_modes = slice::from_raw_parts((*resources).modes, (*resources).nmode as usize);
|
||||
let output_modes = &output_info.modes;
|
||||
let resource_modes = resources.modes();
|
||||
|
||||
let modes = resource_modes
|
||||
.iter()
|
||||
|
|
@ -81,7 +70,7 @@ impl XConnection {
|
|||
.filter(|x| output_modes.iter().any(|id| x.id == *id))
|
||||
.map(|mode| {
|
||||
VideoMode {
|
||||
size: (mode.width, mode.height),
|
||||
size: (mode.width.into(), mode.height.into()),
|
||||
refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode)
|
||||
.unwrap_or(0),
|
||||
bit_depth: bit_depth as u16,
|
||||
|
|
@ -93,11 +82,13 @@ impl XConnection {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let name_slice = slice::from_raw_parts(
|
||||
(*output_info).name as *mut u8,
|
||||
(*output_info).nameLen as usize,
|
||||
);
|
||||
let name = String::from_utf8_lossy(name_slice).into();
|
||||
let name = match str::from_utf8(&output_info.name) {
|
||||
Ok(name) => name.to_owned(),
|
||||
Err(err) => {
|
||||
warn!("Failed to get output name: {:?}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
// Override DPI if `WINIT_X11_SCALE_FACTOR` variable is set
|
||||
let deprecated_dpi_override = env::var("WINIT_HIDPI_FACTOR").ok();
|
||||
if deprecated_dpi_override.is_some() {
|
||||
|
|
@ -124,8 +115,8 @@ impl XConnection {
|
|||
|
||||
let scale_factor = match dpi_env {
|
||||
EnvVarDPI::Randr => calc_dpi_factor(
|
||||
((*crtc).width, (*crtc).height),
|
||||
((*output_info).mm_width as _, (*output_info).mm_height as _),
|
||||
(crtc.width.into(), crtc.height.into()),
|
||||
(output_info.mm_width as _, output_info.mm_height as _),
|
||||
),
|
||||
EnvVarDPI::Scale(dpi_override) => {
|
||||
if !validate_scale_factor(dpi_override) {
|
||||
|
|
@ -140,74 +131,47 @@ impl XConnection {
|
|||
dpi / 96.
|
||||
} else {
|
||||
calc_dpi_factor(
|
||||
((*crtc).width, (*crtc).height),
|
||||
((*output_info).mm_width as _, (*output_info).mm_height as _),
|
||||
(crtc.width.into(), crtc.height.into()),
|
||||
(output_info.mm_width as _, output_info.mm_height as _),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(self.xrandr.XRRFreeOutputInfo)(output_info);
|
||||
Some((name, scale_factor, modes))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn set_crtc_config(&self, crtc_id: RRCrtc, mode_id: RRMode) -> Option<()> {
|
||||
unsafe {
|
||||
let mut major = 0;
|
||||
let mut minor = 0;
|
||||
(self.xrandr.XRRQueryVersion)(self.display, &mut major, &mut minor);
|
||||
pub fn set_crtc_config(
|
||||
&self,
|
||||
crtc_id: randr::Crtc,
|
||||
mode_id: randr::Mode,
|
||||
) -> Result<(), X11Error> {
|
||||
let crtc = self
|
||||
.xcb_connection()
|
||||
.randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?
|
||||
.reply()?;
|
||||
|
||||
let root = self.default_root().root;
|
||||
let resources = if (major == 1 && minor >= 3) || major > 1 {
|
||||
(self.xrandr.XRRGetScreenResourcesCurrent)(self.display, root as ffi::Window)
|
||||
} else {
|
||||
(self.xrandr.XRRGetScreenResources)(self.display, root as ffi::Window)
|
||||
};
|
||||
|
||||
let crtc = (self.xrandr.XRRGetCrtcInfo)(self.display, resources, crtc_id);
|
||||
let status = (self.xrandr.XRRSetCrtcConfig)(
|
||||
self.display,
|
||||
resources,
|
||||
self.xcb_connection()
|
||||
.randr_set_crtc_config(
|
||||
crtc_id,
|
||||
CurrentTime,
|
||||
(*crtc).x,
|
||||
(*crtc).y,
|
||||
crtc.timestamp,
|
||||
x11rb::CURRENT_TIME,
|
||||
crtc.x,
|
||||
crtc.y,
|
||||
mode_id,
|
||||
(*crtc).rotation,
|
||||
(*crtc).outputs.offset(0),
|
||||
1,
|
||||
);
|
||||
|
||||
(self.xrandr.XRRFreeCrtcInfo)(crtc);
|
||||
(self.xrandr.XRRFreeScreenResources)(resources);
|
||||
|
||||
if status == Success as i32 {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
crtc.rotation,
|
||||
&crtc.outputs,
|
||||
)?
|
||||
.reply()
|
||||
.map(|_| ())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn get_crtc_mode(&self, crtc_id: RRCrtc) -> RRMode {
|
||||
unsafe {
|
||||
let mut major = 0;
|
||||
let mut minor = 0;
|
||||
(self.xrandr.XRRQueryVersion)(self.display, &mut major, &mut minor);
|
||||
|
||||
let root = self.default_root().root;
|
||||
let resources = if (major == 1 && minor >= 3) || major > 1 {
|
||||
(self.xrandr.XRRGetScreenResourcesCurrent)(self.display, root as ffi::Window)
|
||||
} else {
|
||||
(self.xrandr.XRRGetScreenResources)(self.display, root as ffi::Window)
|
||||
};
|
||||
|
||||
let crtc = (self.xrandr.XRRGetCrtcInfo)(self.display, resources, crtc_id);
|
||||
let mode = (*crtc).mode;
|
||||
(self.xrandr.XRRFreeCrtcInfo)(crtc);
|
||||
(self.xrandr.XRRFreeScreenResources)(resources);
|
||||
mode
|
||||
}
|
||||
pub fn get_crtc_mode(&self, crtc_id: randr::Crtc) -> Result<randr::Mode, X11Error> {
|
||||
Ok(self
|
||||
.xcb_connection()
|
||||
.randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?
|
||||
.reply()?
|
||||
.mode)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue