1
0
Fork 0
forked from wry/wry

Merge pull request #709 from kotarac/renderer-small-windows

rect: safer construction
This commit is contained in:
mahkoh 2026-01-09 09:47:28 +01:00 committed by GitHub
commit 5fed1d999f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 245 additions and 159 deletions

View file

@ -2991,7 +2991,7 @@ impl RenderBuffer {
pub fn damage_full(&self) {
let dmabuf = self.dev_bo.dmabuf();
let rect = Rect::new_sized_unchecked(0, 0, dmabuf.width, dmabuf.height);
let rect = Rect::new_sized_saturating(0, 0, dmabuf.width, dmabuf.height);
self.damage_queue.clear_all();
self.damage_queue.damage(&[rect]);
}

View file

@ -332,7 +332,7 @@ impl CursorImageScaled {
yhot: i32,
) -> Result<Rc<Self>, CursorError> {
Ok(Rc::new(Self {
extents: Rect::new_sized(-xhot, -yhot, width, height).unwrap(),
extents: Rect::new_sized_saturating(-xhot, -yhot, width, height),
tex: ctx
.clone()
.shmem_texture(None, data, ARGB8888, width, height, width * 4, None)?,

View file

@ -495,7 +495,7 @@ impl CursorUser {
y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32;
}
let (width, height) = output.global.pixel_size();
if !extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) {
if !extents.intersects(&Rect::new_sized_saturating(-x_rel, -y_rel, width, height)) {
if render {
output.hardware_cursor_needs_render.set(true);
}

View file

@ -235,7 +235,7 @@ impl DamageMatrix {
let y1 = (y1 as f64 * self.my + self.dy).floor() as i32 + dy;
let x2 = (x2 as f64 * self.mx + self.dx).ceil() as i32 + dx;
let y2 = (y2 as f64 * self.my + self.dy).ceil() as i32 + dy;
Rect::new(x1, y1, x2, y2).unwrap()
Rect::new_saturating(x1, y1, x2, y2)
}
pub fn new(

View file

@ -187,7 +187,7 @@ impl FramebufferRect {
let x2 = ((x2 + 1.0) / 2.0 * width).round() as i32;
let y1 = ((y1 + 1.0) / 2.0 * height).round() as i32;
let y2 = ((y2 + 1.0) / 2.0 * height).round() as i32;
Rect::new(x1, y1, x2, y2).unwrap_or_default()
Rect::new_saturating(x1, y1, x2, y2)
}
}
@ -314,7 +314,7 @@ pub trait GfxFramebuffer: Debug {
fn full_region(&self) -> Region {
let (width, height) = self.physical_size();
Region::new(Rect::new_sized_unchecked(0, 0, width, height))
Region::new(Rect::new_sized_saturating(0, 0, width, height))
}
}
@ -616,7 +616,7 @@ impl dyn GfxFramebuffer {
logical_extents: Rect::new_empty(0, 0),
pixel_extents: {
let (width, height) = self.logical_size(transform);
Rect::new(0, 0, width, height).unwrap()
Rect::new_saturating(0, 0, width, height)
},
icons: None,
};
@ -945,7 +945,7 @@ pub fn create_render_pass(
logical_extents: node.node_absolute_position().at_point(0, 0),
pixel_extents: {
let (width, height) = logical_size(physical_size, transform);
Rect::new(0, 0, width, height).unwrap()
Rect::new_saturating(0, 0, width, height)
},
icons: state.icons.get(state, scale),
};

View file

@ -102,7 +102,12 @@ impl VulkanShmImage {
data.data_copied.set(true);
data.buffer.set(Some(buffer.clone()));
if img.contents_are_undefined.get() {
damage = Region::new(Rect::new_sized(0, 0, img.width as _, img.height as _).unwrap());
damage = Region::new(Rect::new_sized_saturating(
0,
0,
img.width as _,
img.height as _,
));
}
self.calculate_copies(img, data, damage, buffer.offset);
self.async_release_from_gfx_queue(img, data, TransferType::Upload)?;
@ -186,7 +191,12 @@ impl VulkanShmImage {
if tt == TransferType::Download {
return Err(VulkanError::UndefinedContents);
}
damage = Region::new(Rect::new_sized(0, 0, img.width as _, img.height as _).unwrap());
damage = Region::new(Rect::new_sized_saturating(
0,
0,
img.width as _,
img.height as _,
));
}
let copies = &mut *self.calculate_copies(img, data, damage, 0);
@ -471,15 +481,12 @@ impl VulkanShmImage {
job.work.bpp = img.format.bpp as _;
job.work.rects.clear();
for copy in copies {
job.work.rects.push(
Rect::new_sized(
copy.image_offset.x as _,
copy.image_offset.y as _,
copy.image_extent.width as _,
copy.image_extent.height as _,
)
.unwrap(),
);
job.work.rects.push(Rect::new_sized_saturating(
copy.image_offset.x as _,
copy.image_offset.y as _,
copy.image_extent.width as _,
copy.image_extent.height as _,
));
}
pending = data.cpu.submit(job);
}

View file

@ -86,7 +86,7 @@ impl WlBuffer {
id,
destroyed: Cell::new(false),
client: client.clone(),
rect: Rect::new_sized(0, 0, width, height).unwrap(),
rect: Rect::new_sized_saturating(0, 0, width, height),
format,
width,
height,
@ -154,7 +154,7 @@ impl WlBuffer {
id,
destroyed: Cell::new(false),
client: client.clone(),
rect: Rect::new_sized(0, 0, width, height).unwrap(),
rect: Rect::new_sized_saturating(0, 0, width, height),
format,
dmabuf: None,
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
@ -183,7 +183,7 @@ impl WlBuffer {
id,
destroyed: Cell::new(false),
client: client.clone(),
rect: Rect::new_sized(0, 0, 1, 1).unwrap(),
rect: Rect::new_sized_saturating(0, 0, 1, 1),
format: ARGB8888,
dmabuf: None,
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),

View file

@ -216,7 +216,7 @@ impl WlOutputGlobal {
name,
state: state.clone(),
connector: connector.clone(),
pos: Cell::new(Rect::new_sized(x, y, width, height).unwrap()),
pos: Cell::new(Rect::new_sized_saturating(x, y, width, height)),
output_id: output_id.clone(),
mode: Cell::new(connector_state.mode),
refresh_nsec: Cell::new(connector_state.mode.refresh_nsec()),
@ -343,7 +343,7 @@ impl WlOutputGlobal {
self.damage_matrix.set(matrix);
self.connector
.damage_intersect
.set(Rect::new_sized_unchecked(0, 0, mode.width, mode.height));
.set(Rect::new_sized_saturating(0, 0, mode.width, mode.height));
}
pub fn add_damage_area(&self, area: &Rect) {

View file

@ -47,7 +47,9 @@ impl WlRegionRequestHandler for WlRegion {
return Err(WlRegionError::NegativeExtents);
}
let mut region = self.region.borrow_mut();
region.add(Rect::new_sized(req.x, req.y, req.width, req.height).unwrap());
region.add(Rect::new_sized_saturating(
req.x, req.y, req.width, req.height,
));
Ok(())
}
@ -56,7 +58,9 @@ impl WlRegionRequestHandler for WlRegion {
return Err(WlRegionError::NegativeExtents);
}
let mut region = self.region.borrow_mut();
region.sub(Rect::new_sized(req.x, req.y, req.width, req.height).unwrap());
region.sub(Rect::new_sized_saturating(
req.x, req.y, req.width, req.height,
));
Ok(())
}
}

View file

@ -195,13 +195,12 @@ fn get_region(
.rects()
.iter()
.map(|r| {
Rect::new_sized(
Rect::new_sized_saturating(
r.x1() / scale,
r.y1() / scale,
r.width() / scale,
r.height() / scale,
)
.unwrap()
})
.collect();
region = Region::from_rects(&rects);

View file

@ -1352,7 +1352,7 @@ impl WlSurface {
if (width, height) != (old_width, old_height) {
self.need_extents_update.set(true);
self.buffer_abs_pos
.set(buffer_abs_pos.with_size(width, height).unwrap());
.set(buffer_abs_pos.with_size_saturating(width, height));
max_surface_size = (width.max(old_width), height.max(old_height));
damage_full = true;
buffer_abs_pos_size_changed = true;
@ -1426,9 +1426,8 @@ impl WlSurface {
self.commit_timeline.set_fifo_barrier();
}
if damage_full && (self.visible.get() || was_visible) {
let mut damage = buffer_abs_pos
.with_size(max_surface_size.0, max_surface_size.1)
.unwrap();
let mut damage =
buffer_abs_pos.with_size_saturating(max_surface_size.0, max_surface_size.1);
if let Some(tl) = self.toplevel.get() {
damage = damage.intersect(tl.node_absolute_position());
}
@ -1519,7 +1518,7 @@ impl WlSurface {
let y1 = damage.y1() / scale;
let x2 = (damage.x2() + scale - 1) / scale;
let y2 = (damage.y2() + scale - 1) / scale;
damage = Rect::new(x1, y1, x2, y2).unwrap();
damage = Rect::new_saturating(x1, y1, x2, y2);
}
damage = damage.intersect(bounds.unwrap_or(pos));
self.client.state.damage(damage);

View file

@ -123,13 +123,12 @@ impl Cursor for CursorSurface {
return rect;
}
let scale = scale.to_f64();
Rect::new(
Rect::new_saturating(
(rect.x1() as f64 * scale).ceil() as _,
(rect.y1() as f64 * scale).ceil() as _,
(rect.x2() as f64 * scale).ceil() as _,
(rect.y2() as f64 * scale).ceil() as _,
)
.unwrap()
}
fn set_output(&self, output: &Rc<OutputNode>) {

View file

@ -142,7 +142,7 @@ impl XwindowData {
let mut width = event.width as i32;
let mut height = event.height as i32;
client_wire_scale_to_logical!(client, x, y, width, height);
let extents = Rect::new_sized(x, y, width, height).unwrap();
let extents = Rect::new_sized_saturating(x, y, width, height);
// log::info!("xwin {} new {:?} or {}", event.window, extents, event.override_redirect);
Self {
state: state.clone(),

View file

@ -536,7 +536,7 @@ impl XdgSurfaceRequestHandler for XdgSurface {
if req.height <= 0 || req.width <= 0 {
return Err(XdgSurfaceError::NonPositiveWidthHeight);
}
let extents = Rect::new_sized(req.x, req.y, req.width, req.height).unwrap();
let extents = Rect::new_sized_saturating(req.x, req.y, req.width, req.height);
self.pending().geometry = Some(extents);
Ok(())
}

View file

@ -207,13 +207,12 @@ impl XdgPopup {
// use its position as is.
if let Some(maybe_abs_pos) = maybe_abs_pos {
abs_pos = maybe_abs_pos;
rel_pos = Rect::new_sized(
rel_pos = Rect::new_sized_saturating(
abs_pos.x1() - parent_abs.x1(),
abs_pos.y1() - parent_abs.y1(),
abs_pos.width(),
abs_pos.height(),
)
.unwrap();
);
}
}
}

View file

@ -514,7 +514,7 @@ impl ZwlrLayerSurfaceV1 {
} else if anchor.contains(BOTTOM) {
y1 = oheight - height - mb;
}
let a_rect = Rect::new_sized(x1 + rect.x1(), y1 + rect.y1(), width, height).unwrap();
let a_rect = Rect::new_sized_saturating(x1 + rect.x1(), y1 + rect.y1(), width, height);
let o_rect = a_rect.move_(-opos.x1(), -opos.y1());
self.output_extents.set(o_rect);
let a_rect_old = self.pos.replace(a_rect);

View file

@ -132,7 +132,7 @@ impl XdgPositioned {
y1 -= self.size_height / 2;
}
Rect::new_sized(x1, y1, self.size_width, self.size_height).unwrap()
Rect::new_sized_saturating(x1, y1, self.size_width, self.size_height)
}
}
@ -185,7 +185,7 @@ impl XdgPositionerRequestHandler for XdgPositioner {
return Err(XdgPositionerError::NegativeAnchorRect);
}
let mut position = self.position.borrow_mut();
position.ar = Rect::new_sized(req.x, req.y, req.width, req.height).unwrap();
position.ar = Rect::new_sized_saturating(req.x, req.y, req.width, req.height);
Ok(())
}

View file

@ -109,14 +109,14 @@ impl ZwlrScreencopyManagerV1 {
return Ok(());
};
let mode = global.mode.get();
let mut rect = Rect::new_sized(0, 0, mode.width, mode.height).unwrap();
let mut rect = Rect::new_sized_saturating(0, 0, mode.width, mode.height);
if let Some(region) = region {
let scale = global.persistent.scale.get().to_f64();
let x1 = (region.x1() as f64 * scale).round() as i32;
let y1 = (region.y1() as f64 * scale).round() as i32;
let x2 = (region.x2() as f64 * scale).round() as i32;
let y2 = (region.y2() as f64 * scale).round() as i32;
let region = Rect::new(x1, y1, x2, y2).unwrap();
let region = Rect::new_saturating(x1, y1, x2, y2);
rect = rect.intersect(region);
}
let frame = Rc::new(ZwlrScreencopyFrameV1 {

View file

@ -16,7 +16,10 @@ use {
Axis, Direction,
input::{InputDevice, Seat},
keyboard::{Keymap, ModifiedKeySym},
theme::{BarPosition, sized::BAR_SEPARATOR_WIDTH},
theme::{
BarPosition,
sized::{BAR_SEPARATOR_WIDTH, Resizable},
},
video::{Connector, Transform},
},
std::{cell::Cell, ops::Deref, ptr, rc::Rc, time::Duration},
@ -303,11 +306,12 @@ impl TestConfig {
})
}
pub fn set_size(&self, sized: Resizable, size: i32) -> TestResult {
self.send(ClientMessage::SetSize { sized, size })
}
pub fn set_bar_separator_width(&self, width: i32) -> TestResult {
self.send(ClientMessage::SetSize {
sized: BAR_SEPARATOR_WIDTH,
size: width,
})
self.set_size(BAR_SEPARATOR_WIDTH, width)
}
pub fn set_bar_position(&self, position: BarPosition) -> TestResult {
@ -323,6 +327,10 @@ impl TestConfig {
get_response!(reply, GetShowBar { show });
Ok(show)
}
pub fn set_show_titles(&self, show: bool) -> TestResult {
self.send(ClientMessage::SetShowTitles { show })
}
}
impl Drop for TestConfig {

View file

@ -83,6 +83,7 @@ mod t0049_surface_damage_backend;
mod t0050_fifo;
mod t0051_pointer_warp;
mod t0052_bar;
mod t0053_theme;
pub trait TestCase: Sync {
fn name(&self) -> &'static str;
@ -154,5 +155,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
t0050_fifo,
t0051_pointer_warp,
t0052_bar,
t0053_theme,
}
}

View file

@ -0,0 +1,48 @@
use {
crate::it::{test_error::TestError, testrun::TestRun},
jay_config::theme::sized::{BORDER_WIDTH, TITLE_HEIGHT},
std::rc::Rc,
};
testcase!();
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
let setup = run.create_default_setup().await?;
let client = run.create_client().await?;
let win = client.create_window().await?;
win.map().await?;
client.sync().await;
// Make it floating
run.cfg.set_floating(setup.seat.id(), true)?;
run.sync().await;
let float_node = run
.state
.root
.stacked
.iter()
.find_map(|n| Rc::clone(&n).node_into_float())
.unwrap();
let pos = float_node.position.get();
// 1. Huge borders: Ensure renderer doesn't crash when borders are larger than window
let huge_bw = pos.width() / 2 + 10;
run.cfg.set_size(BORDER_WIDTH, huge_bw)?;
run.sync().await;
let _ = client.take_screenshot(false).await?;
// Reset border
run.cfg.set_size(BORDER_WIDTH, 5)?;
run.sync().await;
// 2. Huge title height: Ensure renderer doesn't crash when title is larger than window
let huge_th = pos.height() + 10;
run.cfg.set_size(TITLE_HEIGHT, huge_th)?;
run.cfg.set_show_titles(true)?;
run.sync().await;
let _ = client.take_screenshot(false).await?;
Ok(())
}

View file

@ -374,7 +374,7 @@ impl PangoLayout {
let mut rect = PangoRectangle::default();
pango_layout_get_extents(self.l, &mut rect, ptr::null_mut());
pango_extents_to_pixels(&mut rect, ptr::null_mut());
Rect::new_sized(rect.x, rect.y, rect.width, rect.height).unwrap()
Rect::new_sized_saturating(rect.x, rect.y, rect.width, rect.height)
}
}
@ -383,7 +383,7 @@ impl PangoLayout {
let mut rect = PangoRectangle::default();
pango_layout_get_extents(self.l, ptr::null_mut(), &mut rect);
pango_extents_to_pixels(&mut rect, ptr::null_mut());
Rect::new_sized(rect.x, rect.y, rect.width, rect.height).unwrap()
Rect::new_sized_saturating(rect.x, rect.y, rect.width, rect.height)
}
}

View file

@ -101,11 +101,6 @@ impl Rect {
})
}
#[track_caller]
pub fn new_unchecked(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
Self::new(x1, y1, x2, y2).unwrap()
}
#[cfg_attr(not(test), expect(dead_code))]
fn new_unchecked_danger(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
Self {
@ -126,9 +121,28 @@ impl Rect {
Self::new(x1, y1, x1 + width, y1 + height)
}
#[track_caller]
pub fn new_sized_unchecked(x1: i32, y1: i32, width: i32, height: i32) -> Self {
Self::new_sized(x1, y1, width, height).unwrap()
pub fn new_saturating(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
Self {
raw: RectRaw {
x1,
y1,
x2: x2.max(x1),
y2: y2.max(y1),
tag: NoTag,
},
}
}
pub fn new_sized_saturating(x1: i32, y1: i32, width: i32, height: i32) -> Self {
Self {
raw: RectRaw {
x1,
y1,
x2: x1.saturating_add(width.max(0)),
y2: y1.saturating_add(height.max(0)),
tag: NoTag,
},
}
}
pub fn union(&self, other: Self) -> Self {
@ -159,8 +173,8 @@ impl Rect {
}
}
pub fn with_size(&self, width: i32, height: i32) -> Option<Self> {
Self::new_sized(self.raw.x1, self.raw.y1, width, height)
pub fn with_size_saturating(&self, width: i32, height: i32) -> Self {
Self::new_sized_saturating(self.raw.x1, self.raw.y1, width, height)
}
pub fn with_tag(&self, tag: u32) -> Rect<u32> {

View file

@ -688,3 +688,19 @@ fn intersect3() {
],
);
}
#[test]
fn new_saturating() {
let r1 = Rect::new_sized_saturating(10, 10, -5, -5);
assert!(r1.is_empty());
assert_eq!(r1.x1(), 10);
assert_eq!(r1.x2(), 10);
let r2 = Rect::new_saturating(100, 100, 50, 50);
assert!(r2.is_empty());
assert_eq!(r2.x1(), 100);
assert_eq!(r2.x2(), 100);
let r3 = Rect::new_sized_saturating(i32::MAX - 10, 0, 100, 10);
assert_eq!(r3.x2(), i32::MAX);
}

View file

@ -521,18 +521,27 @@ impl Renderer<'_> {
};
let uc = theme.colors.separator.get();
let borders = [
Rect::new_sized(x, y, pos.width(), bw).unwrap(),
Rect::new_sized(x, y + bw, bw, pos.height() - bw).unwrap(),
Rect::new_sized(x + pos.width() - bw, y + bw, bw, pos.height() - bw).unwrap(),
Rect::new_sized(x + bw, y + pos.height() - bw, pos.width() - 2 * bw, bw).unwrap(),
Rect::new_sized_saturating(x, y, pos.width(), bw),
Rect::new_sized_saturating(x, y + bw, bw, pos.height() - bw),
Rect::new_sized_saturating(x + pos.width() - bw, y + bw, bw, pos.height() - bw),
Rect::new_sized_saturating(x + bw, y + pos.height() - bw, pos.width() - 2 * bw, bw),
];
let srgb_srgb = self.state.color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear;
self.base.fill_boxes(&borders, &bc, srgb);
let title = [Rect::new_sized(x + bw, y + bw, pos.width() - 2 * bw, th).unwrap()];
let title = [Rect::new_sized_saturating(
x + bw,
y + bw,
pos.width() - 2 * bw,
th,
)];
self.base.fill_boxes(&title, &tc, srgb);
let title_underline =
[Rect::new_sized(x + bw, y + bw + th, pos.width() - 2 * bw, tuh).unwrap()];
let title_underline = [Rect::new_sized_saturating(
x + bw,
y + bw + th,
pos.width() - 2 * bw,
tuh,
)];
self.base.fill_boxes(&title_underline, &uc, srgb);
let rect = floating.title_rect.get().move_(x, y);
let bounds = self.base.scale_rect(rect);
@ -590,13 +599,12 @@ impl Renderer<'_> {
srgb_srgb,
);
}
let body = Rect::new_sized(
let body = Rect::new_sized_saturating(
x + bw,
y + bw + tpuh,
pos.width() - 2 * bw,
pos.height() - 2 * bw - tpuh,
)
.unwrap();
);
let scissor_body = self.base.scale_rect(body);
child.node_render(self, body.x1(), body.y1(), Some(&scissor_body));
}

View file

@ -49,7 +49,7 @@ impl RendererBase<'_> {
let [x1, y1, x2, y2] =
self.scale
.pixel_size([rect.x1(), rect.y1(), rect.x2(), rect.y2()]);
rect = Rect::new(x1, y1, x2, y2).unwrap();
rect = Rect::new_saturating(x1, y1, x2, y2);
}
rect
}

View file

@ -839,7 +839,7 @@ impl State {
}
y1 -= self.theme.sizes.border_width.get() + self.theme.title_plus_underline_height();
x1 -= self.theme.sizes.border_width.get();
Rect::new_sized(x1, y1, width, height).unwrap()
Rect::new_sized_saturating(x1, y1, width, height)
} else {
let mut x1 = output_rect.x1();
let mut y1 = output_rect.y1();
@ -853,7 +853,7 @@ impl State {
} else {
height = output_rect.height();
}
Rect::new_sized(x1, y1, width, height).unwrap()
Rect::new_sized_saturating(x1, y1, width, height)
};
FloatNode::new(self, workspace, position, node.clone());
self.focus_after_map(node, self.seat_queue.last().as_deref());
@ -1228,7 +1228,7 @@ impl State {
logical_extents: position.at_point(0, 0),
pixel_extents: {
let (width, height) = target.logical_size(target_transform);
Rect::new_sized(0, 0, width, height).unwrap()
Rect::new_sized_saturating(0, 0, width, height)
},
icons: None,
};

View file

@ -632,7 +632,7 @@ impl CpuJob for RenderJob {
.async_upload_from_buffer(
&gfx_buffer,
data.clone(),
Region::new(Rect::new_sized_unchecked(0, 0, rt.width, rt.height)),
Region::new(Rect::new_sized_saturating(0, 0, rt.width, rt.height)),
)
.map_err(TextError::Upload)
} else {
@ -650,7 +650,7 @@ impl CpuJob for RenderJob {
&staging,
data.clone(),
Rc::new(data.memfd.data(rt.stride, rt.height)),
Region::new(Rect::new_sized_unchecked(0, 0, rt.width, rt.height)),
Region::new(Rect::new_sized_saturating(0, 0, rt.width, rt.height)),
)
.map_err(TextError::Upload)
};

View file

@ -185,7 +185,7 @@ impl ContainerChild {
// let y1 = body.y1() + (body.height() - height) / 2;
let x1 = body.x1();
let y1 = body.y1();
content = Rect::new_sized(x1, y1, width, height).unwrap();
content = Rect::new_sized_saturating(x1, y1, width, height);
// log::debug!("body: {:?}", body);
// log::debug!("content: {:?}", content);
self.content.set(content);
@ -382,15 +382,12 @@ impl ContainerNode {
}
fn damage(&self) {
self.state.damage(
Rect::new_sized(
self.abs_x1.get(),
self.abs_y1.get(),
self.width.get(),
self.height.get(),
)
.unwrap(),
);
self.state.damage(Rect::new_sized_saturating(
self.abs_x1.get(),
self.abs_y1.get(),
self.width.get(),
self.height.get(),
));
}
fn schedule_layout(self: &Rc<Self>) {
@ -442,7 +439,7 @@ impl ContainerNode {
}
child
.title_rect
.set(Rect::new_sized(pos, 0, width, th).unwrap());
.set(Rect::new_sized_saturating(pos, 0, width, th));
pos += width + bw;
}
}
@ -483,7 +480,7 @@ impl ContainerNode {
body_size,
),
};
let body = Rect::new_sized(x1, y1, width, height).unwrap();
let body = Rect::new_sized_saturating(x1, y1, width, height);
child.body.set(body);
pos += body_size + border_width;
if split == ContainerSplit::Vertical {
@ -523,7 +520,7 @@ impl ContainerNode {
)
}
};
body = Rect::new_sized(x1, y1, width, height).unwrap();
body = Rect::new_sized_saturating(x1, y1, width, height);
child.body.set(body);
pos += size + border_width;
if split == ContainerSplit::Vertical {
@ -534,15 +531,12 @@ impl ContainerNode {
self.sum_factors.set(1.0);
for child in self.children.iter() {
let body = child.body.get();
child.title_rect.set(
Rect::new_sized(
body.x1(),
body.y1() - title_plus_underline_height,
body.width(),
title_height_tmp,
)
.unwrap(),
);
child.title_rect.set(Rect::new_sized_saturating(
body.x1(),
body.y1() - title_plus_underline_height,
body.width(),
title_height_tmp,
));
let body = body.move_(self.abs_x1.get(), self.abs_y1.get());
child.node.clone().tl_change_extents(&body);
child.position_content();
@ -573,15 +567,12 @@ impl ContainerNode {
self.content_width.set(self.width.get());
}
}
self.mono_body.set(
Rect::new_sized(
0,
title_plus_underline_height,
self.width.get(),
self.height.get().sub(title_plus_underline_height).max(0),
)
.unwrap(),
);
self.mono_body.set(Rect::new_sized_saturating(
0,
title_plus_underline_height,
self.width.get(),
self.height.get() - title_plus_underline_height,
));
}
fn pointer_move(
@ -837,7 +828,7 @@ impl ContainerNode {
for (i, child) in self.children.iter().enumerate() {
let rect = child.title_rect.get();
if self.toplevel_data.visible.get() && !mono && split != ContainerSplit::Horizontal {
self.state.damage(Rect::new_sized_unchecked(
self.state.damage(Rect::new_sized_saturating(
abs_x,
abs_y + rect.y1(),
cwidth,
@ -846,13 +837,13 @@ impl ContainerNode {
}
if i > 0 {
let rect = if mono {
Rect::new_sized(rect.x1() - bw, 0, bw, th)
Rect::new_sized_saturating(rect.x1() - bw, 0, bw, th)
} else if split == ContainerSplit::Horizontal {
Rect::new_sized(rect.x1() - bw, 0, bw, cheight)
Rect::new_sized_saturating(rect.x1() - bw, 0, bw, cheight)
} else {
Rect::new_sized(0, rect.y1() - bw, cwidth, bw)
Rect::new_sized_saturating(0, rect.y1() - bw, cwidth, bw)
};
rd.border_rects.push(rect.unwrap());
rd.border_rects.push(rect);
}
if child.active.get() {
rd.active_title_rects.push(rect);
@ -864,7 +855,7 @@ impl ContainerNode {
rd.title_rects.push(rect);
}
if !mono {
let rect = Rect::new_sized(rect.x1(), rect.y2(), rect.width(), 1).unwrap();
let rect = Rect::new_sized_saturating(rect.x1(), rect.y2(), rect.width(), 1);
rd.underline_rects.push(rect);
}
let tt = &*child.title_tex.borrow();
@ -877,11 +868,11 @@ impl ContainerNode {
}
if mono {
rd.underline_rects
.push(Rect::new_sized(0, th, cwidth, tuh).unwrap());
.push(Rect::new_sized_saturating(0, th, cwidth, tuh));
}
if self.toplevel_data.visible.get() && (mono || split == ContainerSplit::Horizontal) {
self.state
.damage(Rect::new_sized_unchecked(abs_x, abs_y, cwidth, tpuh));
.damage(Rect::new_sized_saturating(abs_x, abs_y, cwidth, tpuh));
}
rd.titles.remove_if(|_, v| v.is_empty());
}
@ -1192,7 +1183,7 @@ impl ContainerNode {
}
fn update_child_size(&self, node: &NodeRef<ContainerChild>, width: i32, height: i32) {
let rect = Rect::new(0, 0, width, height).unwrap();
let rect = Rect::new_saturating(0, 0, width, height);
node.content.set(rect);
node.position_content();
if let Some(mono) = self.mono_child.get()
@ -1633,13 +1624,12 @@ impl Node for ContainerNode {
}
fn node_absolute_position(&self) -> Rect {
Rect::new_sized(
Rect::new_sized_saturating(
self.abs_x1.get(),
self.abs_y1.get(),
self.width.get(),
self.height.get(),
)
.unwrap()
}
fn node_output(&self) -> Option<Rc<OutputNode>> {
@ -2381,14 +2371,14 @@ fn tile_drag_destination_in_mono(
split_before = false;
y1 = y2 - dy;
} else {
let rect = Rect::new_unchecked(x1, y1 + dy, x2, y2 - dy);
let rect = Rect::new_saturating(x1, y1 + dy, x2, y2 - dy);
return TileDragDestination {
highlight: rect,
ty: TddType::Replace(tl),
};
}
}
let rect = Rect::new_unchecked(x1, y1, x2, y2);
let rect = Rect::new_saturating(x1, y1, x2, y2);
TileDragDestination {
highlight: rect,
ty: TddType::Split {
@ -2434,7 +2424,7 @@ fn tile_drag_destination_in_split(
x1 = x2 - dx;
}
swap!();
let rect = Rect::new(x1, y1, x2, y2).unwrap();
let rect = Rect::new_saturating(x1, y1, x2, y2);
let ty = if split_before || split_after {
TddType::Split {
node: tl,

View file

@ -66,7 +66,7 @@ impl DisplayNode {
y1 = 0;
y2 = 0;
}
self.extents.set(Rect::new(x1, y1, x2, y2).unwrap());
self.extents.set(Rect::new_saturating(x1, y1, x2, y2));
}
pub fn update_visible(&self, state: &State) {

View file

@ -179,14 +179,13 @@ impl FloatNode {
let bw = theme.sizes.border_width.get();
let th = theme.title_height();
let tpuh = theme.title_plus_underline_height();
let cpos = Rect::new_sized(
let cpos = Rect::new_sized_saturating(
pos.x1() + bw,
pos.y1() + bw + tpuh,
(pos.width() - 2 * bw).max(0),
(pos.height() - 2 * bw - tpuh).max(0),
)
.unwrap();
let tr = Rect::new_sized(bw, bw, (pos.width() - 2 * bw).max(0), th).unwrap();
pos.width() - 2 * bw,
pos.height() - 2 * bw - tpuh,
);
let tr = Rect::new_sized_saturating(bw, bw, pos.width() - 2 * bw, th);
child.clone().tl_change_extents(&cpos);
self.title_rect.set(tr);
self.layout_scheduled.set(false);
@ -261,7 +260,7 @@ impl FloatNode {
let pos = self.position.get();
if self.visible.get() && pos.width() >= 2 * bw {
let tr =
Rect::new_sized(pos.x1() + bw, pos.y1() + bw, pos.width() - 2 * bw, th).unwrap();
Rect::new_sized_saturating(pos.x1() + bw, pos.y1() + bw, pos.width() - 2 * bw, th);
self.state.damage(tr);
}
}
@ -349,7 +348,7 @@ impl FloatNode {
y2 = y2.max(y1 + 2 * bw + tpuh);
}
}
let new_pos = Rect::new(x1, y1, x2, y2).unwrap();
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
self.position.set(new_pos);
if self.visible.get() {
self.state.damage(pos);
@ -463,7 +462,7 @@ impl FloatNode {
y1 = opos.y1();
y2 += y1 - pos.y1();
}
let new_pos = Rect::new(x1, y1, x2, y2).unwrap();
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
self.position.set(new_pos);
if self.visible.get() {
self.state.damage(pos);
@ -970,7 +969,7 @@ impl ContainingNode for FloatNode {
if let Some(v) = new_y2 {
y2 = (v + bw).max(y1 + bw + tpuh + bw);
}
let new_pos = Rect::new(x1, y1, x2, y2).unwrap();
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
if new_pos != pos {
self.position.set(new_pos);
if self.visible.get() {

View file

@ -619,7 +619,7 @@ impl OutputNode {
});
}
}
let rect = Rect::new_sized(pos, y1, title_width, bar_rect_rel.height()).unwrap();
let rect = Rect::new_sized_saturating(pos, y1, title_width, bar_rect_rel.height());
if Some(ws.id) == active_id {
rd.active_workspace = Some(OutputWorkspaceRenderData {
rect,
@ -768,9 +768,9 @@ impl OutputNode {
let x1 = rect.x1() + exclusive.left;
let width = (x2 - x1).max(0);
let height = (y2 - y1).max(0);
let non_exclusive_rect = Rect::new_sized_unchecked(x1, y1, width, height);
let non_exclusive_rect = Rect::new_sized_saturating(x1, y1, width, height);
let non_exclusive_rect_rel =
Rect::new_sized_unchecked(exclusive.left, exclusive.top, width, height);
Rect::new_sized_saturating(exclusive.left, exclusive.top, width, height);
let mut bar_rect = Rect::default();
let mut bar_rect_rel = Rect::default();
let mut bar_rect_with_separator = Rect::default();
@ -781,24 +781,19 @@ impl OutputNode {
let bar_separator_rect;
match self.state.theme.bar_position.get() {
BarPosition::Bottom => {
workspace_rect =
Rect::new_sized_unchecked(x1, y1, width, (height - bh - bsw).max(0));
workspace_rect = Rect::new_sized_saturating(x1, y1, width, height - bh - bsw);
bar_rect_with_separator =
Rect::new_sized_unchecked(x1, y1 + height - bh - bsw, width, bh + bsw);
Rect::new_sized_saturating(x1, y1 + height - bh - bsw, width, bh + bsw);
bar_separator_rect =
Rect::new_sized_unchecked(x1, y1 + height - bh - bsw, width, bsw);
bar_rect = Rect::new_sized_unchecked(x1, y1 + height - bh, width, bh);
Rect::new_sized_saturating(x1, y1 + height - bh - bsw, width, bsw);
bar_rect = Rect::new_sized_saturating(x1, y1 + height - bh, width, bh);
}
BarPosition::Top | _ => {
bar_rect = Rect::new_sized_unchecked(x1, y1, width, bh);
bar_separator_rect = Rect::new_sized_unchecked(x1, y1 + bh, width, bsw);
bar_rect_with_separator = Rect::new_sized_unchecked(x1, y1, width, bh + bsw);
workspace_rect = Rect::new_sized_unchecked(
x1,
y1 + bh + bsw,
width,
(height - bh - bsw).max(0),
);
bar_rect = Rect::new_sized_saturating(x1, y1, width, bh);
bar_separator_rect = Rect::new_sized_saturating(x1, y1 + bh, width, bsw);
bar_rect_with_separator = Rect::new_sized_saturating(x1, y1, width, bh + bsw);
workspace_rect =
Rect::new_sized_saturating(x1, y1 + bh + bsw, width, height - bh - bsw);
}
}
bar_rect_rel = bar_rect.move_(-rect.x1(), -rect.y1());
@ -888,7 +883,7 @@ impl OutputNode {
pos: (i32, i32),
) -> Rect {
let (width, height) = calculate_logical_size((mode.width, mode.height), transform, scale);
Rect::new_sized(pos.0, pos.1, width, height).unwrap()
Rect::new_sized_saturating(pos.0, pos.1, width, height)
}
fn change_extents_(self: &Rc<Self>, rect: &Rect) {
@ -1420,7 +1415,7 @@ impl OutputNode {
}
have_any = true;
right -= bar_rect.height();
let rel_pos = Rect::new_sized(right, 1, icon_size, icon_size).unwrap();
let rel_pos = Rect::new_sized_saturating(right, 1, icon_size, icon_size);
let abs_pos = rel_pos.move_(bar_rect.x1(), bar_rect.y1());
item.set_position(abs_pos, rel_pos);
}
@ -1431,13 +1426,12 @@ impl OutputNode {
if prev_right != right {
{
let min = prev_right.min(right);
let rect = Rect::new(
let rect = Rect::new_saturating(
bar_rect.x1() + min,
bar_rect.y1(),
bar_rect.x2(),
bar_rect.y2(),
)
.unwrap();
);
self.state.damage(rect);
}
self.schedule_update_render_data();

View file

@ -2173,7 +2173,7 @@ impl Wm {
self.set_net_client_list().await;
let pending = data.info.pending_extents.get();
if pending.width() > 0 && pending.height() > 0 {
let dummy = Rect::new_sized(0, 0, 1, 1).unwrap();
let dummy = Rect::new_sized_saturating(0, 0, 1, 1);
for rect in [dummy, pending] {
let mut x = rect.x1();
let mut y = rect.y1();
@ -2264,7 +2264,7 @@ impl Wm {
let mut width = event.width as i32;
let mut height = event.height as i32;
client_wire_scale_to_logical!(self.client, x, y, width, height);
let extents = Rect::new_sized(x, y, width, height).unwrap();
let extents = Rect::new_sized_saturating(x, y, width, height);
if let Some(window) = data.window.get() {
window.tl_change_extents(&extents);
self.state.tree_changed();
@ -2309,7 +2309,7 @@ impl Wm {
}
data.info
.pending_extents
.set(Rect::new_sized(x1, y1, width, height).unwrap());
.set(Rect::new_sized_saturating(x1, y1, width, height));
Ok(())
}