Make with_x11_visual take ID instead of a pointer

At the moment, the with_x11_visual function takes a pointer and
immediately dereferences it to get the visual info inside. As it is safe
to pass a null pointer to this function, it is unsound. This commit
replaces the pointer parameter with a visual ID, and then uses that ID
to look up the actual visual under
the X11 setup. As this is what was already practically happening before,
this change shouldn't cause any performance downgrades.

This is a breaking change, but it's done in the name of soundness so it
should be okay. It should be trivial for end users to accommodate it,
as it's just a matter of getting the visual ID from the pointer to the
visual before passing it in.

Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
John Nunley 2023-08-05 14:58:23 -07:00 committed by GitHub
parent 8100a6a584
commit 584aab4cd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 31 deletions

View file

@ -24,7 +24,7 @@ use std::time::Duration;
#[cfg(x11_platform)]
pub use self::x11::XNotSupported;
#[cfg(x11_platform)]
use self::x11::{ffi::XVisualInfo, util::WindowType as XWindowType, X11Error, XConnection, XError};
use self::x11::{util::WindowType as XWindowType, X11Error, XConnection, XError};
#[cfg(x11_platform)]
use crate::platform::x11::XlibErrorHook;
use crate::{
@ -96,7 +96,7 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub name: Option<ApplicationName>,
pub activation_token: Option<ActivationToken>,
#[cfg(x11_platform)]
pub visual_infos: Option<XVisualInfo>,
pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
#[cfg(x11_platform)]
pub screen_id: Option<i32>,
#[cfg(x11_platform)]
@ -113,7 +113,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
name: None,
activation_token: None,
#[cfg(x11_platform)]
visual_infos: None,
visual_id: None,
#[cfg(x11_platform)]
screen_id: None,
#[cfg(x11_platform)]

View file

@ -886,6 +886,9 @@ pub enum X11Error {
/// Got an invalid activation token.
InvalidActivationToken(Vec<u8>),
/// Could not find a matching X11 visual for this visualid
NoSuchVisual(xproto::Visualid),
}
impl fmt::Display for X11Error {
@ -902,6 +905,13 @@ impl fmt::Display for X11Error {
"Invalid activation token: {}",
std::str::from_utf8(s).unwrap_or("<invalid utf8>")
),
X11Error::NoSuchVisual(visualid) => {
write!(
f,
"Could not find a matching X11 visual for ID `{:x}`",
visualid
)
}
}
}
}

View file

@ -214,30 +214,45 @@ impl UnownedWindow {
None => xconn.default_screen_index() as c_int,
};
// An iterator over all of the visuals combined with their depths.
let mut all_visuals = xconn
.xcb_connection()
.setup()
.roots
.iter()
.flat_map(|root| &root.allowed_depths)
.flat_map(|depth| {
depth
.visuals
.iter()
.map(move |visual| (visual, depth.depth))
});
// creating
let (visual, depth, require_colormap) = match pl_attribs.visual_infos {
Some(vi) => (vi.visualid as _, vi.depth as _, false),
let (visualtype, depth, require_colormap) = match pl_attribs.visual_id {
Some(vi) => {
// Find this specific visual.
let (visualtype, depth) = all_visuals
.find(|(visual, _)| visual.visual_id == vi)
.ok_or_else(|| os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())))?;
(Some(visualtype), depth, true)
}
None if window_attrs.transparent => {
// Find a suitable visual, true color with 32 bits of depth.
xconn.xcb_connection().setup().roots
.iter()
.flat_map(|root| &root.allowed_depths)
.filter(|depth| depth.depth == 32)
.flat_map(|depth| depth.visuals.iter().map(move |visual| (visual, depth.depth)))
.find(|(visual, _)| {
visual.class == xproto::VisualClass::TRUE_COLOR
all_visuals
.find_map(|(visual, depth)| {
(visual.class == xproto::VisualClass::TRUE_COLOR)
.then_some((Some(visual), depth, true))
})
.map_or_else(|| {
.unwrap_or_else(|| {
debug!("Could not set transparency, because XMatchVisualInfo returned zero for the required parameters");
(x11rb::COPY_FROM_PARENT as _, x11rb::COPY_FROM_PARENT as _, false)
}, |(visual, depth)| (visual.visual_id, depth, true))
(None as _, x11rb::COPY_FROM_PARENT as _, false)
})
}
_ => (
x11rb::COPY_FROM_PARENT as _,
x11rb::COPY_FROM_PARENT as _,
false,
),
_ => (None, x11rb::COPY_FROM_PARENT as _, false),
};
let visual = visualtype.map_or(x11rb::COPY_FROM_PARENT, |v| v.visual_id);
let window_attributes = {
use xproto::EventMask;
@ -260,8 +275,8 @@ impl UnownedWindow {
}
// Add a colormap if needed.
let colormap_visual = match pl_attribs.visual_infos {
Some(vi) => Some(vi.visualid as u32),
let colormap_visual = match pl_attribs.visual_id {
Some(vi) => Some(vi),
None if require_colormap => Some(visual),
_ => None,
};