use smithay::utils::{Logical, Rectangle, Size}; use smithay::wayland::compositor::SurfaceData; use crate::wayland::protocols::corner_radius::{ CacheableCorners, CacheablePadding, CornerRadiusData, CornerRadiusHandler, CornerRadiusState, CornerRadiusSurface, delegate_corner_radius, }; use crate::state::State; impl CornerRadiusHandler for State { fn corner_radius_state(&mut self) -> &mut CornerRadiusState { &mut self.common.corner_radius_state } fn set_corner_radius(&mut self, data: &CornerRadiusData) { if force_redraw(self, data).is_none() { tracing::warn!("Failed to force redraw for corner radius change."); } } fn unset_corner_radius(&mut self, data: &CornerRadiusData) { if force_redraw(self, data).is_none() { tracing::warn!("Failed to force redraw for corner radius reset."); } } fn set_padding(&mut self, data: &CornerRadiusData) { if force_redraw(self, data).is_none() { tracing::warn!("Failed to force redraw for corner radius change."); } } fn unset_padding(&mut self, data: &CornerRadiusData) { if force_redraw(self, data).is_none() { tracing::warn!("Failed to force redraw for corner radius reset."); } } } fn force_redraw(state: &mut State, data: &CornerRadiusData) -> Option<()> { let guard = data.lock().unwrap(); let shell = state.common.shell.read(); let output = match &guard.surface { CornerRadiusSurface::Toplevel(toplevel) => { let toplevel = toplevel.upgrade().ok()?; let surface = state.common.xdg_shell_state.get_toplevel(&toplevel)?; shell.visible_output_for_surface(surface.wl_surface())? } CornerRadiusSurface::Popup(popup) => { let popup = popup.upgrade().ok()?; let surface = state.common.xdg_shell_state.get_popup(&popup)?; shell.visible_output_for_surface(surface.wl_surface())? } CornerRadiusSurface::Layer(layer) => { let layer = layer.upgrade().ok()?; let surface = state .common .layer_shell_state .layer_surfaces() .find(|l| l.shell_surface() == &layer)?; shell.visible_output_for_surface(surface.wl_surface())? } }; state.backend.schedule_render(output); Some(()) } pub fn surface_corners(states: &SurfaceData, size: Size) -> Option<[u8; 4]> { let mut guard = states.cached_state.get::(); // guard against corner radius being too large, potentially disconnecting the outline let half_min_dim = u8::try_from(size.w.min(size.h) / 2).unwrap_or(u8::MAX); let corners = guard.current().0?; Some([ u8::try_from(corners.top_left) .unwrap_or(u8::MAX) .min(half_min_dim), u8::try_from(corners.top_right) .unwrap_or(u8::MAX) .min(half_min_dim), u8::try_from(corners.bottom_right) .unwrap_or(u8::MAX) .min(half_min_dim), u8::try_from(corners.bottom_left) .unwrap_or(u8::MAX) .min(half_min_dim), ]) } pub fn surface_padding(states: &SurfaceData, size: Size) -> Option<[i32; 4]> { let mut guard = states.cached_state.get::(); let padding = guard.current().0?; // guard against padding being too large Some([ padding.top.min(size.h / 2), padding.right.min(size.w / 2), padding.bottom.min(size.h / 2), padding.left.min(size.w / 2), ]) } pub fn pad_rect( mut rect: Rectangle, padding: &[i32; 4], ) -> Option> { rect.size.h = rect.size.h.checked_sub(padding[0])?; rect.loc.x += padding[3]; rect.size.w = rect.size.w.checked_sub(padding[1])?; rect.size.h = rect.size.h.checked_sub(padding[2])?; rect.size.w = rect.size.w.checked_sub(padding[3])?; rect.loc.y += padding[0]; Some(rect) } delegate_corner_radius!(State);