diff --git a/src/wayland/handlers/corner_radius.rs b/src/wayland/handlers/corner_radius.rs index 7991d6b0..bec18d09 100644 --- a/src/wayland/handlers/corner_radius.rs +++ b/src/wayland/handlers/corner_radius.rs @@ -1,9 +1,12 @@ use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v1; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; -use smithay::wayland::shell::xdg::ToplevelSurface; +use smithay::reexports::wayland_server::Resource; +use smithay::wayland::compositor::{add_pre_commit_hook, with_states}; +use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface}; use crate::wayland::protocols::corner_radius::{ - delegate_corner_radius, CornerRadiusData, CornerRadiusHandler, CornerRadiusState, + delegate_corner_radius, CacheableCorners, CornerRadiusData, CornerRadiusHandler, + CornerRadiusState, }; use crate::state::State; @@ -39,6 +42,45 @@ impl CornerRadiusHandler for State { tracing::warn!("Failed to force redraw for corner radius reset."); } } + + fn add_corners( + &mut self, + toplevel: &xdg_toplevel::XdgToplevel, + toplevel_obj: cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, + ) { + if let Some(surface) = self.toplevel_from_resource(&toplevel) { + add_pre_commit_hook::(surface.wl_surface(), move |_, _dh, surface| { + let corner_radii_too_big = with_states(surface, |surface_data| { + let corners = surface_data + .cached_state + .get::() + .pending() + .clone(); + surface_data + .cached_state + .get::() + .pending() + .geometry + .zip(corners.0.as_ref()) + .is_some_and(|(geo, corners)| { + let half_min_dim = + u8::try_from(geo.size.w.min(geo.size.h) / 2).unwrap_or(u8::MAX); + corners.top_right > half_min_dim + || corners.top_left > half_min_dim + || corners.bottom_right > half_min_dim + || corners.bottom_left > half_min_dim + }) + }); + + if corner_radii_too_big { + toplevel_obj.post_error( + cosmic_corner_radius_toplevel_v1::Error::RadiusTooLarge as u32, + format!("{toplevel_obj:?} corner radius too large"), + ); + } + }); + } + } } fn force_redraw(state: &mut State, data: &CornerRadiusData) -> Option<()> { diff --git a/src/wayland/protocols/corner_radius.rs b/src/wayland/protocols/corner_radius.rs index 77d18e40..2dbc9158 100644 --- a/src/wayland/protocols/corner_radius.rs +++ b/src/wayland/protocols/corner_radius.rs @@ -45,6 +45,11 @@ impl CornerRadiusState { } pub trait CornerRadiusHandler { + fn add_corners( + &mut self, + toplevel: &XdgToplevel, + toplevel_obj: cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, + ); fn corner_radius_state(&mut self) -> &mut CornerRadiusState; fn toplevel_from_resource(&mut self, toplevel: &XdgToplevel) -> Option; fn set_corner_radius( @@ -111,7 +116,8 @@ where toplevel: toplevel.downgrade(), corners: None, }); - let _ = data_init.init(id, data); + let obj = data_init.init(id, data); + state.add_corners(&toplevel, obj); } _ => unimplemented!(), } @@ -151,12 +157,16 @@ where cosmic_corner_radius_toplevel_v1::Request::Destroy => { let mut guard = data.lock().unwrap(); guard.corners = None; - if let Some(surface) = guard - .toplevel - .upgrade() - .ok() - .and_then(|toplevel| state.toplevel_from_resource(&toplevel)) - { + + let Ok(toplevel) = guard.toplevel.upgrade() else { + resource.post_error( + cosmic_corner_radius_toplevel_v1::Error::ToplevelDestroyed as u32, + format!("{:?} No toplevel found", resource), + ); + return; + }; + + if let Some(surface) = state.toplevel_from_resource(&toplevel) { with_states(surface.wl_surface(), |s| { let mut cached = s.cached_state.get::(); let pending = cached.pending(); @@ -175,12 +185,15 @@ where } => { let mut guard = data.lock().unwrap(); guard.set_corner_radius(top_left, top_right, bottom_right, bottom_left); - if let Some(surface) = guard - .toplevel - .upgrade() - .ok() - .and_then(|toplevel| state.toplevel_from_resource(&toplevel)) - { + let Ok(toplevel) = guard.toplevel.upgrade() else { + resource.post_error( + cosmic_corner_radius_toplevel_v1::Error::ToplevelDestroyed as u32, + format!("{:?} No toplevel found", resource), + ); + return; + }; + + if let Some(surface) = state.toplevel_from_resource(&toplevel) { with_states(surface.wl_surface(), |s| { let mut cached = s.cached_state.get::(); let pending = cached.pending(); @@ -194,12 +207,15 @@ where cosmic_corner_radius_toplevel_v1::Request::UnsetRadius => { let mut guard = data.lock().unwrap(); guard.corners = None; - if let Some(surface) = guard - .toplevel - .upgrade() - .ok() - .and_then(|toplevel| state.toplevel_from_resource(&toplevel)) - { + let Ok(toplevel) = guard.toplevel.upgrade() else { + resource.post_error( + cosmic_corner_radius_toplevel_v1::Error::ToplevelDestroyed as u32, + format!("{:?} No toplevel found", resource), + ); + return; + }; + + if let Some(surface) = state.toplevel_from_resource(&toplevel) { with_states(surface.wl_surface(), |s| { let mut cached = s.cached_state.get::(); let pending = cached.pending();