refactor(corner-radius): cleanup & add pre commit hooks

This commit is contained in:
Ashley Wulber 2025-09-26 12:12:04 -04:00 committed by Victoria Brekenfeld
parent 819887e298
commit 2e3bb2d80e
2 changed files with 109 additions and 74 deletions

View file

@ -1,11 +1,7 @@
use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v1; use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v1;
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
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::{ use crate::wayland::protocols::corner_radius::{
delegate_corner_radius, CacheableCorners, CornerRadiusData, CornerRadiusHandler, delegate_corner_radius, CornerRadiusData, CornerRadiusHandler,
CornerRadiusState, CornerRadiusState,
}; };
@ -16,13 +12,6 @@ impl CornerRadiusHandler for State {
&mut self.common.corner_radius_state &mut self.common.corner_radius_state
} }
fn toplevel_from_resource(
&mut self,
toplevel: &xdg_toplevel::XdgToplevel,
) -> Option<ToplevelSurface> {
self.common.xdg_shell_state.get_toplevel(toplevel)
}
fn set_corner_radius( fn set_corner_radius(
&mut self, &mut self,
_: &cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, _: &cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1,
@ -42,45 +31,6 @@ impl CornerRadiusHandler for State {
tracing::warn!("Failed to force redraw for corner radius reset."); 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::<Self, _>(surface.wl_surface(), move |_, _dh, surface| {
let corner_radii_too_big = with_states(surface, |surface_data| {
let corners = surface_data
.cached_state
.get::<CacheableCorners>()
.pending()
.clone();
surface_data
.cached_state
.get::<SurfaceCachedState>()
.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<()> { fn force_redraw(state: &mut State, data: &CornerRadiusData) -> Option<()> {

View file

@ -1,13 +1,21 @@
use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1;
use cosmic_protocols::corner_radius::v1::server::{ use cosmic_protocols::corner_radius::v1::server::{
cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1, cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1,
}; };
use smithay::reexports::{ use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel, use smithay::utils::HookId;
wayland_server::{Client, Dispatch, DisplayHandle, GlobalDispatch, Resource, Weak}, use smithay::wayland::compositor::add_pre_commit_hook;
};
use smithay::wayland::compositor::with_states; use smithay::wayland::compositor::with_states;
use smithay::wayland::compositor::Cacheable; use smithay::wayland::compositor::Cacheable;
use smithay::wayland::shell::xdg::ToplevelSurface; use smithay::wayland::shell::xdg::SurfaceCachedState;
use smithay::{
reexports::{
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
wayland_server::{Client, Dispatch, DisplayHandle, GlobalDispatch, Resource, Weak},
},
wayland::shell::xdg::XdgShellHandler,
};
use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
use wayland_backend::server::GlobalId; use wayland_backend::server::GlobalId;
@ -44,14 +52,8 @@ impl CornerRadiusState {
} }
} }
pub trait CornerRadiusHandler { pub trait CornerRadiusHandler: XdgShellHandler {
fn add_corners(
&mut self,
toplevel: &XdgToplevel,
toplevel_obj: cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1,
);
fn corner_radius_state(&mut self) -> &mut CornerRadiusState; fn corner_radius_state(&mut self) -> &mut CornerRadiusState;
fn toplevel_from_resource(&mut self, toplevel: &XdgToplevel) -> Option<ToplevelSurface>;
fn set_corner_radius( fn set_corner_radius(
&mut self, &mut self,
toplevel: &cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, toplevel: &cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1,
@ -100,7 +102,7 @@ where
fn request( fn request(
state: &mut D, state: &mut D,
_client: &Client, _client: &Client,
_resource: &cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, resource: &cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1,
request: <cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1 as smithay::reexports::wayland_server::Resource>::Request, request: <cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1 as smithay::reexports::wayland_server::Resource>::Request,
_data: &(), _data: &(),
_dhandle: &DisplayHandle, _dhandle: &DisplayHandle,
@ -109,15 +111,85 @@ where
match request { match request {
cosmic_corner_radius_manager_v1::Request::Destroy => { cosmic_corner_radius_manager_v1::Request::Destroy => {
let corner_radius_state = state.corner_radius_state(); let corner_radius_state = state.corner_radius_state();
corner_radius_state.instances.retain(|i| i != _resource); corner_radius_state.instances.retain(|i| i != resource);
} }
cosmic_corner_radius_manager_v1::Request::GetCornerRadius { id, toplevel } => { cosmic_corner_radius_manager_v1::Request::GetCornerRadius { id, toplevel } => {
let data = Mutex::new(CornerRadiusInternal { if let Some(surface) = state.xdg_shell_state().get_toplevel(&toplevel) {
toplevel: toplevel.downgrade(), let radius_exists = with_states(surface.wl_surface(), |surface_data| {
corners: None, let hook_ids = surface_data.data_map.get_or_insert_threadsafe(|| {
}); Mutex::new(HashMap::<
let obj = data_init.init(id, data); WlSurface,
state.add_corners(&toplevel, obj); (HookId, Weak<CosmicCornerRadiusToplevelV1>),
>::new())
});
let guard = hook_ids.lock().unwrap();
guard
.get(surface.wl_surface())
.map(|(_, t)| t.upgrade().is_ok())
});
if radius_exists.unwrap_or_default() {
resource.post_error(
cosmic_corner_radius_manager_v1::Error::CornerRadiusExists as u32,
format!("{resource:?} CosmicCornerRadiusToplevelV1 object already exists for the surface"),
);
}
let data = Mutex::new(CornerRadiusInternal {
toplevel: toplevel.downgrade(),
corners: None,
});
let obj = data_init.init(id, data);
let obj_downgrade = obj.downgrade();
let needs_hook = radius_exists.is_none();
if needs_hook {
let hook_id = add_pre_commit_hook::<D, _>(
surface.wl_surface(),
move |_, _dh, surface| {
let corner_radii_too_big = with_states(surface, |surface_data| {
let corners = surface_data
.cached_state
.get::<CacheableCorners>()
.pending()
.clone();
surface_data
.cached_state
.get::<SurfaceCachedState>()
.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 {
obj.post_error(
cosmic_corner_radius_toplevel_v1::Error::RadiusTooLarge
as u32,
format!("{obj:?} corner radius too large"),
);
}
},
);
with_states(surface.wl_surface(), |surface_data| {
let hook_ids = surface_data.data_map.get_or_insert_threadsafe(|| {
Mutex::new(HashMap::<
WlSurface,
(HookId, Weak<CosmicCornerRadiusToplevelV1>),
>::new())
});
let mut guard = hook_ids.lock().unwrap();
guard.insert(surface.wl_surface().clone(), (hook_id, obj_downgrade));
});
}
}
} }
_ => unimplemented!(), _ => unimplemented!(),
} }
@ -166,7 +238,20 @@ where
return; return;
}; };
if let Some(surface) = state.toplevel_from_resource(&toplevel) { if let Some(surface) = state.xdg_shell_state().get_toplevel(&toplevel) {
with_states(surface.wl_surface(), |surface_data| {
if let Some(hook_ids_mutex) =
surface_data.data_map.get::<Mutex<
HashMap<WlSurface, (HookId, Weak<CosmicCornerRadiusToplevelV1>)>,
>>()
{
let mut hook_ids = hook_ids_mutex.lock().unwrap();
hook_ids.remove(surface.wl_surface());
}
});
}
if let Some(surface) = state.xdg_shell_state().get_toplevel(&toplevel) {
with_states(surface.wl_surface(), |s| { with_states(surface.wl_surface(), |s| {
let mut cached = s.cached_state.get::<CacheableCorners>(); let mut cached = s.cached_state.get::<CacheableCorners>();
let pending = cached.pending(); let pending = cached.pending();
@ -193,7 +278,7 @@ where
return; return;
}; };
if let Some(surface) = state.toplevel_from_resource(&toplevel) { if let Some(surface) = state.xdg_shell_state().get_toplevel(&toplevel) {
with_states(surface.wl_surface(), |s| { with_states(surface.wl_surface(), |s| {
let mut cached = s.cached_state.get::<CacheableCorners>(); let mut cached = s.cached_state.get::<CacheableCorners>();
let pending = cached.pending(); let pending = cached.pending();
@ -215,7 +300,7 @@ where
return; return;
}; };
if let Some(surface) = state.toplevel_from_resource(&toplevel) { if let Some(surface) = state.xdg_shell_state().get_toplevel(&toplevel) {
with_states(surface.wl_surface(), |s| { with_states(surface.wl_surface(), |s| {
let mut cached = s.cached_state.get::<CacheableCorners>(); let mut cached = s.cached_state.get::<CacheableCorners>();
let pending = cached.pending(); let pending = cached.pending();