diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 239beafa..e07187eb 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -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]); } diff --git a/src/cursor.rs b/src/cursor.rs index 583632cb..65c1ee39 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -332,7 +332,7 @@ impl CursorImageScaled { yhot: i32, ) -> Result, 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)?, diff --git a/src/cursor_user.rs b/src/cursor_user.rs index f983e577..19310269 100644 --- a/src/cursor_user.rs +++ b/src/cursor_user.rs @@ -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); } diff --git a/src/damage.rs b/src/damage.rs index fa5a753d..4de915e9 100644 --- a/src/damage.rs +++ b/src/damage.rs @@ -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( diff --git a/src/gfx_api.rs b/src/gfx_api.rs index 5193f40b..6fbddab2 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -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), }; diff --git a/src/gfx_apis/vulkan/transfer.rs b/src/gfx_apis/vulkan/transfer.rs index e7378c07..eca55277 100644 --- a/src/gfx_apis/vulkan/transfer.rs +++ b/src/gfx_apis/vulkan/transfer.rs @@ -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); } diff --git a/src/ifs/wl_buffer.rs b/src/ifs/wl_buffer.rs index 22fc251a..127c656c 100644 --- a/src/ifs/wl_buffer.rs +++ b/src/ifs/wl_buffer.rs @@ -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()), diff --git a/src/ifs/wl_output.rs b/src/ifs/wl_output.rs index dd055b61..d3680364 100644 --- a/src/ifs/wl_output.rs +++ b/src/ifs/wl_output.rs @@ -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) { diff --git a/src/ifs/wl_region.rs b/src/ifs/wl_region.rs index 3331b78a..d65c1761 100644 --- a/src/ifs/wl_region.rs +++ b/src/ifs/wl_region.rs @@ -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(()) } } diff --git a/src/ifs/wl_seat/zwp_pointer_constraints_v1.rs b/src/ifs/wl_seat/zwp_pointer_constraints_v1.rs index 540764af..519915b2 100644 --- a/src/ifs/wl_seat/zwp_pointer_constraints_v1.rs +++ b/src/ifs/wl_seat/zwp_pointer_constraints_v1.rs @@ -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); diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 770d4571..4dd47217 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -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); diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 2f5b5cd3..54f9aa51 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -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) { diff --git a/src/ifs/wl_surface/x_surface/xwindow.rs b/src/ifs/wl_surface/x_surface/xwindow.rs index 60e5e24e..a1761d18 100644 --- a/src/ifs/wl_surface/x_surface/xwindow.rs +++ b/src/ifs/wl_surface/x_surface/xwindow.rs @@ -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(), diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index 4814c95b..9b5130d7 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -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(()) } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 0710a5ad..14b131fe 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -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(); + ); } } } diff --git a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs index 8ec5a308..f865798f 100644 --- a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs +++ b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs @@ -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); diff --git a/src/ifs/xdg_positioner.rs b/src/ifs/xdg_positioner.rs index 36fdb118..76ca6764 100644 --- a/src/ifs/xdg_positioner.rs +++ b/src/ifs/xdg_positioner.rs @@ -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(()) } diff --git a/src/ifs/zwlr_screencopy_manager_v1.rs b/src/ifs/zwlr_screencopy_manager_v1.rs index 89cb3f70..57471b3e 100644 --- a/src/ifs/zwlr_screencopy_manager_v1.rs +++ b/src/ifs/zwlr_screencopy_manager_v1.rs @@ -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 { diff --git a/src/it/test_config.rs b/src/it/test_config.rs index 446a675a..56ee5272 100644 --- a/src/it/test_config.rs +++ b/src/it/test_config.rs @@ -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 { diff --git a/src/it/tests.rs b/src/it/tests.rs index ce79d2b3..543b84bb 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -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, } } diff --git a/src/it/tests/t0053_theme.rs b/src/it/tests/t0053_theme.rs new file mode 100644 index 00000000..170e11f0 --- /dev/null +++ b/src/it/tests/t0053_theme.rs @@ -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) -> 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(()) +} diff --git a/src/pango.rs b/src/pango.rs index 0b4ac9b7..cd78b351 100644 --- a/src/pango.rs +++ b/src/pango.rs @@ -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) } } diff --git a/src/rect.rs b/src/rect.rs index f384b1ef..dad62b06 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -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::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 { diff --git a/src/rect/tests.rs b/src/rect/tests.rs index 76bde61f..c40c7efe 100644 --- a/src/rect/tests.rs +++ b/src/rect/tests.rs @@ -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); +} diff --git a/src/renderer.rs b/src/renderer.rs index b28d5787..6f7efd46 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -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)); } diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index 0c582e33..4d544998 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -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 } diff --git a/src/state.rs b/src/state.rs index 4a95b242..31dcb69f 100644 --- a/src/state.rs +++ b/src/state.rs @@ -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, }; diff --git a/src/text.rs b/src/text.rs index f05f1e82..effa7f2c 100644 --- a/src/text.rs +++ b/src/text.rs @@ -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) }; diff --git a/src/tree/container.rs b/src/tree/container.rs index 7aab26a2..7f48f2b1 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -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) { @@ -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, 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> { @@ -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, diff --git a/src/tree/display.rs b/src/tree/display.rs index 1d9ab082..440916bf 100644 --- a/src/tree/display.rs +++ b/src/tree/display.rs @@ -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) { diff --git a/src/tree/float.rs b/src/tree/float.rs index 817f525d..ccad4860 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -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() { diff --git a/src/tree/output.rs b/src/tree/output.rs index 11b8b0a6..ba78da11 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -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, 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(); diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index 179dcc34..67db3a3b 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -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(()) }