Use u32/NonZeroU32 for Rect, and return error if out of range
This commit is contained in:
parent
199a016f44
commit
a147a15d45
6 changed files with 129 additions and 136 deletions
129
src/x11.rs
129
src/x11.rs
|
|
@ -10,7 +10,12 @@ use crate::{Rect, SoftBufferError};
|
|||
use nix::libc::{shmat, shmctl, shmdt, shmget, IPC_PRIVATE, IPC_RMID};
|
||||
use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle};
|
||||
use std::ptr::{null_mut, NonNull};
|
||||
use std::{fmt, io, mem, num::NonZeroU32, rc::Rc, slice};
|
||||
use std::{
|
||||
fmt, io, mem,
|
||||
num::{NonZeroU16, NonZeroU32},
|
||||
rc::Rc,
|
||||
slice,
|
||||
};
|
||||
|
||||
use x11_dl::xlib::Display;
|
||||
use x11_dl::xlib_xcb::Xlib_xcb;
|
||||
|
|
@ -110,11 +115,8 @@ pub struct X11Impl {
|
|||
/// Buffer has been presented.
|
||||
buffer_presented: bool,
|
||||
|
||||
/// The current buffer width.
|
||||
width: u16,
|
||||
|
||||
/// The current buffer height.
|
||||
height: u16,
|
||||
/// The current buffer width/height.
|
||||
size: Option<(NonZeroU16, NonZeroU16)>,
|
||||
}
|
||||
|
||||
/// The buffer that is being drawn to.
|
||||
|
|
@ -227,8 +229,7 @@ impl X11Impl {
|
|||
depth: geometry_reply.depth,
|
||||
buffer,
|
||||
buffer_presented: false,
|
||||
width: 0,
|
||||
height: 0,
|
||||
size: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -246,27 +247,22 @@ impl X11Impl {
|
|||
);
|
||||
|
||||
// Width and height should fit in u16.
|
||||
let width: u16 = width
|
||||
.get()
|
||||
let width: NonZeroU16 = width
|
||||
.try_into()
|
||||
.or(Err(SoftBufferError::SizeOutOfRange { width, height }))?;
|
||||
let height: u16 = height
|
||||
.get()
|
||||
.try_into()
|
||||
.or(Err(SoftBufferError::SizeOutOfRange {
|
||||
width: NonZeroU32::new(width.into()).unwrap(),
|
||||
height,
|
||||
}))?;
|
||||
let height: NonZeroU16 = height.try_into().or(Err(SoftBufferError::SizeOutOfRange {
|
||||
width: width.into(),
|
||||
height,
|
||||
}))?;
|
||||
|
||||
if width != self.width || height != self.height {
|
||||
if self.size != Some((width, height)) {
|
||||
self.buffer_presented = false;
|
||||
self.buffer
|
||||
.resize(&self.display.connection, width, height)
|
||||
.resize(&self.display.connection, width.get(), height.get())
|
||||
.swbuf_err("Failed to resize X11 buffer")?;
|
||||
|
||||
// We successfully resized the buffer.
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.size = Some((width, height));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -311,6 +307,10 @@ impl<'a> BufferImpl<'a> {
|
|||
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||
let imp = self.0;
|
||||
|
||||
let (surface_width, surface_height) = imp
|
||||
.size
|
||||
.expect("Must set size of surface before calling `present_with_damage()`");
|
||||
|
||||
log::trace!("present: window={:X}", imp.window);
|
||||
|
||||
match imp.buffer {
|
||||
|
|
@ -324,8 +324,8 @@ impl<'a> BufferImpl<'a> {
|
|||
xproto::ImageFormat::Z_PIXMAP,
|
||||
imp.window,
|
||||
imp.gc,
|
||||
imp.width,
|
||||
imp.height,
|
||||
surface_width.get(),
|
||||
surface_height.get(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -334,6 +334,7 @@ impl<'a> BufferImpl<'a> {
|
|||
)
|
||||
.map(|c| c.ignore_error())
|
||||
.push_err()
|
||||
.swbuf_err("Failed to draw image to window")?;
|
||||
}
|
||||
|
||||
Buffer::Shm(ref mut shm) => {
|
||||
|
|
@ -343,46 +344,50 @@ impl<'a> BufferImpl<'a> {
|
|||
if let Some((_, segment_id)) = shm.seg {
|
||||
damage
|
||||
.iter()
|
||||
.try_for_each(
|
||||
|Rect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
}| {
|
||||
imp.display
|
||||
.connection
|
||||
.shm_put_image(
|
||||
imp.window,
|
||||
imp.gc,
|
||||
imp.width,
|
||||
imp.height,
|
||||
*x as u16,
|
||||
*y as u16,
|
||||
*width as u16,
|
||||
*height as u16,
|
||||
*x as i16,
|
||||
*y as i16,
|
||||
imp.depth,
|
||||
xproto::ImageFormat::Z_PIXMAP.into(),
|
||||
false,
|
||||
segment_id,
|
||||
0,
|
||||
)
|
||||
.push_err()
|
||||
.map(|c| c.ignore_error())
|
||||
},
|
||||
)
|
||||
.try_for_each(|rect| {
|
||||
let (src_x, src_y, dst_x, dst_y, width, height) = (|| {
|
||||
Some((
|
||||
u16::try_from(rect.x).ok()?,
|
||||
u16::try_from(rect.y).ok()?,
|
||||
i16::try_from(rect.x).ok()?,
|
||||
i16::try_from(rect.y).ok()?,
|
||||
u16::try_from(rect.width.get()).ok()?,
|
||||
u16::try_from(rect.height.get()).ok()?,
|
||||
))
|
||||
})(
|
||||
)
|
||||
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
|
||||
imp.display
|
||||
.connection
|
||||
.shm_put_image(
|
||||
imp.window,
|
||||
imp.gc,
|
||||
surface_width.get(),
|
||||
surface_height.get(),
|
||||
src_x,
|
||||
src_y,
|
||||
width,
|
||||
height,
|
||||
dst_x,
|
||||
dst_y,
|
||||
imp.depth,
|
||||
xproto::ImageFormat::Z_PIXMAP.into(),
|
||||
false,
|
||||
segment_id,
|
||||
0,
|
||||
)
|
||||
.push_err()
|
||||
.map(|c| c.ignore_error())
|
||||
.swbuf_err("Failed to draw image to window")
|
||||
})
|
||||
.and_then(|()| {
|
||||
// Send a short request to act as a notification for when the X server is done processing the image.
|
||||
shm.begin_wait(&imp.display.connection)
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
.swbuf_err("Failed to draw image to window")
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
.swbuf_err("Failed to draw image to window")?;
|
||||
|
||||
imp.buffer_presented = true;
|
||||
|
||||
|
|
@ -390,13 +395,15 @@ impl<'a> BufferImpl<'a> {
|
|||
}
|
||||
|
||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||
let width = self.0.width.into();
|
||||
let height = self.0.height.into();
|
||||
let (width, height) = self
|
||||
.0
|
||||
.size
|
||||
.expect("Must set size of surface before calling `present()`");
|
||||
self.present_with_damage(&[Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
width: width.into(),
|
||||
height: height.into(),
|
||||
}])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue