1+ use cosmic_protocols:: corner_radius:: v1:: server:: cosmic_corner_radius_toplevel_v1:: CosmicCornerRadiusToplevelV1 ;
12use cosmic_protocols:: corner_radius:: v1:: server:: {
23 cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1,
34} ;
4- use smithay:: reexports:: {
5- wayland_protocols:: xdg:: shell:: server:: xdg_toplevel:: XdgToplevel ,
6- wayland_server:: { Client , Dispatch , DisplayHandle , GlobalDispatch , Resource , Weak } ,
7- } ;
5+ use smithay:: reexports:: wayland_server:: protocol:: wl_surface:: WlSurface ;
6+ use smithay:: utils:: HookId ;
7+ use smithay:: wayland:: compositor:: add_pre_commit_hook;
88use smithay:: wayland:: compositor:: with_states;
99use smithay:: wayland:: compositor:: Cacheable ;
10- use smithay:: wayland:: shell:: xdg:: ToplevelSurface ;
10+ use smithay:: wayland:: shell:: xdg:: SurfaceCachedState ;
11+ use smithay:: {
12+ reexports:: {
13+ wayland_protocols:: xdg:: shell:: server:: xdg_toplevel:: XdgToplevel ,
14+ wayland_server:: { Client , Dispatch , DisplayHandle , GlobalDispatch , Resource , Weak } ,
15+ } ,
16+ wayland:: shell:: xdg:: XdgShellHandler ,
17+ } ;
18+ use std:: collections:: HashMap ;
1119use std:: sync:: Mutex ;
1220use wayland_backend:: server:: GlobalId ;
1321
@@ -44,14 +52,8 @@ impl CornerRadiusState {
4452 }
4553}
4654
47- pub trait CornerRadiusHandler {
48- fn add_corners (
49- & mut self ,
50- toplevel : & XdgToplevel ,
51- toplevel_obj : cosmic_corner_radius_toplevel_v1:: CosmicCornerRadiusToplevelV1 ,
52- ) ;
55+ pub trait CornerRadiusHandler : XdgShellHandler {
5356 fn corner_radius_state ( & mut self ) -> & mut CornerRadiusState ;
54- fn toplevel_from_resource ( & mut self , toplevel : & XdgToplevel ) -> Option < ToplevelSurface > ;
5557 fn set_corner_radius (
5658 & mut self ,
5759 toplevel : & cosmic_corner_radius_toplevel_v1:: CosmicCornerRadiusToplevelV1 ,
@@ -100,7 +102,7 @@ where
100102 fn request (
101103 state : & mut D ,
102104 _client : & Client ,
103- _resource : & cosmic_corner_radius_manager_v1:: CosmicCornerRadiusManagerV1 ,
105+ resource : & cosmic_corner_radius_manager_v1:: CosmicCornerRadiusManagerV1 ,
104106 request : <cosmic_corner_radius_manager_v1:: CosmicCornerRadiusManagerV1 as smithay:: reexports:: wayland_server:: Resource >:: Request ,
105107 _data : & ( ) ,
106108 _dhandle : & DisplayHandle ,
@@ -109,15 +111,85 @@ where
109111 match request {
110112 cosmic_corner_radius_manager_v1:: Request :: Destroy => {
111113 let corner_radius_state = state. corner_radius_state ( ) ;
112- corner_radius_state. instances . retain ( |i| i != _resource ) ;
114+ corner_radius_state. instances . retain ( |i| i != resource ) ;
113115 }
114116 cosmic_corner_radius_manager_v1:: Request :: GetCornerRadius { id, toplevel } => {
115- let data = Mutex :: new ( CornerRadiusInternal {
116- toplevel : toplevel. downgrade ( ) ,
117- corners : None ,
118- } ) ;
119- let obj = data_init. init ( id, data) ;
120- state. add_corners ( & toplevel, obj) ;
117+ if let Some ( surface) = state. xdg_shell_state ( ) . get_toplevel ( & toplevel) {
118+ let radius_exists = with_states ( surface. wl_surface ( ) , |surface_data| {
119+ let hook_ids = surface_data. data_map . get_or_insert_threadsafe ( || {
120+ Mutex :: new ( HashMap :: <
121+ WlSurface ,
122+ ( HookId , Weak < CosmicCornerRadiusToplevelV1 > ) ,
123+ > :: new ( ) )
124+ } ) ;
125+ let guard = hook_ids. lock ( ) . unwrap ( ) ;
126+ guard
127+ . get ( surface. wl_surface ( ) )
128+ . map ( |( _, t) | t. upgrade ( ) . is_ok ( ) )
129+ } ) ;
130+ if radius_exists. unwrap_or_default ( ) {
131+ resource. post_error (
132+ cosmic_corner_radius_manager_v1:: Error :: CornerRadiusExists as u32 ,
133+ format ! ( "{resource:?} CosmicCornerRadiusToplevelV1 object already exists for the surface" ) ,
134+ ) ;
135+ }
136+ let data = Mutex :: new ( CornerRadiusInternal {
137+ toplevel : toplevel. downgrade ( ) ,
138+ corners : None ,
139+ } ) ;
140+ let obj = data_init. init ( id, data) ;
141+ let obj_downgrade = obj. downgrade ( ) ;
142+
143+ let needs_hook = radius_exists. is_none ( ) ;
144+ if needs_hook {
145+ let hook_id = add_pre_commit_hook :: < D , _ > (
146+ surface. wl_surface ( ) ,
147+ move |_, _dh, surface| {
148+ let corner_radii_too_big = with_states ( surface, |surface_data| {
149+ let corners = surface_data
150+ . cached_state
151+ . get :: < CacheableCorners > ( )
152+ . pending ( )
153+ . clone ( ) ;
154+ surface_data
155+ . cached_state
156+ . get :: < SurfaceCachedState > ( )
157+ . pending ( )
158+ . geometry
159+ . zip ( corners. 0 . as_ref ( ) )
160+ . is_some_and ( |( geo, corners) | {
161+ let half_min_dim =
162+ u8:: try_from ( geo. size . w . min ( geo. size . h ) / 2 )
163+ . unwrap_or ( u8:: MAX ) ;
164+ corners. top_right > half_min_dim
165+ || corners. top_left > half_min_dim
166+ || corners. bottom_right > half_min_dim
167+ || corners. bottom_left > half_min_dim
168+ } )
169+ } ) ;
170+
171+ if corner_radii_too_big {
172+ obj. post_error (
173+ cosmic_corner_radius_toplevel_v1:: Error :: RadiusTooLarge
174+ as u32 ,
175+ format ! ( "{obj:?} corner radius too large" ) ,
176+ ) ;
177+ }
178+ } ,
179+ ) ;
180+
181+ with_states ( surface. wl_surface ( ) , |surface_data| {
182+ let hook_ids = surface_data. data_map . get_or_insert_threadsafe ( || {
183+ Mutex :: new ( HashMap :: <
184+ WlSurface ,
185+ ( HookId , Weak < CosmicCornerRadiusToplevelV1 > ) ,
186+ > :: new ( ) )
187+ } ) ;
188+ let mut guard = hook_ids. lock ( ) . unwrap ( ) ;
189+ guard. insert ( surface. wl_surface ( ) . clone ( ) , ( hook_id, obj_downgrade) ) ;
190+ } ) ;
191+ }
192+ }
121193 }
122194 _ => unimplemented ! ( ) ,
123195 }
@@ -166,7 +238,20 @@ where
166238 return ;
167239 } ;
168240
169- if let Some ( surface) = state. toplevel_from_resource ( & toplevel) {
241+ if let Some ( surface) = state. xdg_shell_state ( ) . get_toplevel ( & toplevel) {
242+ with_states ( surface. wl_surface ( ) , |surface_data| {
243+ if let Some ( hook_ids_mutex) =
244+ surface_data. data_map . get :: < Mutex <
245+ HashMap < WlSurface , ( HookId , Weak < CosmicCornerRadiusToplevelV1 > ) > ,
246+ > > ( )
247+ {
248+ let mut hook_ids = hook_ids_mutex. lock ( ) . unwrap ( ) ;
249+ hook_ids. remove ( surface. wl_surface ( ) ) ;
250+ }
251+ } ) ;
252+ }
253+
254+ if let Some ( surface) = state. xdg_shell_state ( ) . get_toplevel ( & toplevel) {
170255 with_states ( surface. wl_surface ( ) , |s| {
171256 let mut cached = s. cached_state . get :: < CacheableCorners > ( ) ;
172257 let pending = cached. pending ( ) ;
@@ -193,7 +278,7 @@ where
193278 return ;
194279 } ;
195280
196- if let Some ( surface) = state. toplevel_from_resource ( & toplevel) {
281+ if let Some ( surface) = state. xdg_shell_state ( ) . get_toplevel ( & toplevel) {
197282 with_states ( surface. wl_surface ( ) , |s| {
198283 let mut cached = s. cached_state . get :: < CacheableCorners > ( ) ;
199284 let pending = cached. pending ( ) ;
@@ -215,7 +300,7 @@ where
215300 return ;
216301 } ;
217302
218- if let Some ( surface) = state. toplevel_from_resource ( & toplevel) {
303+ if let Some ( surface) = state. xdg_shell_state ( ) . get_toplevel ( & toplevel) {
219304 with_states ( surface. wl_surface ( ) , |s| {
220305 let mut cached = s. cached_state . get :: < CacheableCorners > ( ) ;
221306 let pending = cached. pending ( ) ;
0 commit comments