1use std::{ffi::CStr, mem::ManuallyDrop};
7
8use glib::translate::*;
9
10use crate::{
11 CellArea, CellLayout, CellRenderer, TreeIter, TreeModel, ffi, prelude::*, subclass::prelude::*,
12};
13
14pub struct CellDataFunc {
67 func: ffi::GtkCellLayoutDataFunc,
68 func_data: glib::ffi::gpointer,
69 destroy: glib::ffi::GDestroyNotify,
70}
71
72impl CellDataFunc {
73 pub fn call(
78 &self,
79 cell_layout: &impl IsA<CellLayout>,
80 cell: &impl IsA<CellRenderer>,
81 model: &impl IsA<TreeModel>,
82 iter: &TreeIter,
83 ) {
84 if let Some(func) = self.func.as_ref() {
85 unsafe {
86 func(
87 cell_layout.as_ref().to_glib_none().0,
88 cell.as_ref().to_glib_none().0,
89 model.as_ref().to_glib_none().0,
90 mut_override(iter.to_glib_none().0),
91 self.func_data,
92 );
93 }
94 }
95 }
96}
97
98impl Drop for CellDataFunc {
99 fn drop(&mut self) {
100 if let Some(destroy_ptr) = self.destroy.take() {
101 unsafe {
102 destroy_ptr(self.func_data);
103 }
104 }
105 }
106}
107
108pub trait CellLayoutImpl: ObjectImpl + ObjectSubclass<Type: IsA<CellLayout>> {
109 fn pack_start(&self, cell: &CellRenderer, expand: bool) {
110 self.parent_pack_start(cell, expand);
111 }
112
113 fn pack_end(&self, cell: &CellRenderer, expand: bool) {
114 self.parent_pack_end(cell, expand);
115 }
116
117 fn clear(&self) {
118 self.parent_clear();
119 }
120
121 fn add_attribute(&self, cell: &CellRenderer, attribute: &str, column: i32) {
122 self.parent_add_attribute(cell, attribute, column);
123 }
124
125 fn set_cell_data_func(&self, cell: &CellRenderer, cell_data_func: Option<CellDataFunc>) {
126 self.parent_set_cell_data_func(cell, cell_data_func);
127 }
128
129 fn clear_attributes(&self, cell: &CellRenderer) {
130 self.parent_clear_attributes(cell);
131 }
132
133 fn reorder(&self, cell: &CellRenderer, position: i32) {
134 self.parent_reorder(cell, position);
135 }
136
137 #[doc(alias = "get_cells")]
138 fn cells(&self) -> Vec<CellRenderer> {
139 self.parent_cells()
140 }
141
142 #[doc(alias = "get_area")]
143 fn area(&self) -> Option<CellArea> {
144 self.parent_area()
145 }
146}
147
148pub trait CellLayoutImplExt: CellLayoutImpl {
149 fn parent_pack_start(&self, cell: &CellRenderer, expand: bool) {
150 unsafe {
151 let type_data = Self::type_data();
152 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
153 as *const ffi::GtkCellLayoutIface;
154
155 let func = (*parent_iface)
156 .pack_start
157 .expect("no parent \"pack_start\" implementation");
158 func(
159 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
160 cell.to_glib_none().0,
161 expand.into_glib(),
162 );
163 }
164 }
165
166 fn parent_pack_end(&self, cell: &CellRenderer, expand: bool) {
167 unsafe {
168 let type_data = Self::type_data();
169 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
170 as *const ffi::GtkCellLayoutIface;
171
172 let func = (*parent_iface)
173 .pack_end
174 .expect("no parent \"pack_end\" implementation");
175 func(
176 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
177 cell.to_glib_none().0,
178 expand.into_glib(),
179 );
180 }
181 }
182
183 fn parent_clear(&self) {
184 unsafe {
185 let type_data = Self::type_data();
186 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
187 as *const ffi::GtkCellLayoutIface;
188
189 let func = (*parent_iface)
190 .clear
191 .expect("no parent \"clear\" implementation");
192 func(self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0);
193 }
194 }
195
196 fn parent_add_attribute(&self, cell: &CellRenderer, attribute: &str, column: i32) {
197 unsafe {
198 let type_data = Self::type_data();
199 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
200 as *const ffi::GtkCellLayoutIface;
201
202 let func = (*parent_iface)
203 .add_attribute
204 .expect("no parent \"add_attribute\" implementation");
205 func(
206 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
207 cell.to_glib_none().0,
208 attribute.to_glib_none().0,
209 column,
210 );
211 }
212 }
213
214 fn parent_set_cell_data_func(&self, cell: &CellRenderer, cell_data_func: Option<CellDataFunc>) {
215 unsafe {
216 let type_data = Self::type_data();
217 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
218 as *const ffi::GtkCellLayoutIface;
219
220 let func = (*parent_iface)
221 .set_cell_data_func
222 .expect("no parent \"set_cell_data_func\" implementation");
223
224 let (data_func, data_ptr, destroy_func) = if let Some(cell_data_func) = cell_data_func {
225 let cell_data_func = ManuallyDrop::new(cell_data_func);
228 (
229 cell_data_func.func,
230 cell_data_func.func_data,
231 cell_data_func.destroy,
232 )
233 } else {
234 (None, std::ptr::null_mut(), None)
235 };
236
237 func(
238 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
239 cell.to_glib_none().0,
240 data_func,
241 data_ptr,
242 destroy_func,
243 );
244 }
245 }
246
247 fn parent_clear_attributes(&self, cell: &CellRenderer) {
248 unsafe {
249 let type_data = Self::type_data();
250 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
251 as *const ffi::GtkCellLayoutIface;
252
253 let func = (*parent_iface)
254 .clear_attributes
255 .expect("no parent \"clear_attributes\" implementation");
256 func(
257 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
258 cell.to_glib_none().0,
259 );
260 }
261 }
262
263 fn parent_reorder(&self, cell: &CellRenderer, position: i32) {
264 unsafe {
265 let type_data = Self::type_data();
266 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
267 as *const ffi::GtkCellLayoutIface;
268
269 let func = (*parent_iface)
270 .reorder
271 .expect("no parent \"reorder\" implementation");
272 func(
273 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
274 cell.to_glib_none().0,
275 position,
276 );
277 }
278 }
279
280 fn parent_cells(&self) -> Vec<CellRenderer> {
281 unsafe {
282 let type_data = Self::type_data();
283 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
284 as *const ffi::GtkCellLayoutIface;
285
286 let func = (*parent_iface)
287 .get_cells
288 .expect("no parent \"get_cells\" implementation");
289 FromGlibPtrContainer::from_glib_container(func(
290 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
291 ))
292 }
293 }
294
295 fn parent_area(&self) -> Option<CellArea> {
296 unsafe {
297 let type_data = Self::type_data();
298 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
299 as *const ffi::GtkCellLayoutIface;
300
301 (*parent_iface).get_area.and_then(|func| {
302 from_glib_none(func(
303 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
304 ))
305 })
306 }
307 }
308}
309
310impl<T: CellLayoutImpl> CellLayoutImplExt for T {}
311
312unsafe impl<T: CellLayoutImpl> IsImplementable<T> for CellLayout {
313 fn interface_init(iface: &mut glib::Interface<Self>) {
314 let iface = iface.as_mut();
315
316 if !crate::rt::is_initialized() {
317 panic!("GTK has to be initialized first");
318 }
319
320 iface.pack_start = Some(cell_layout_pack_start::<T>);
321 iface.pack_end = Some(cell_layout_pack_end::<T>);
322 iface.clear = Some(cell_layout_clear::<T>);
323 iface.add_attribute = Some(cell_layout_add_attribute::<T>);
324 iface.set_cell_data_func = Some(cell_layout_set_cell_data_func::<T>);
325 iface.clear_attributes = Some(cell_layout_clear_attributes::<T>);
326 iface.reorder = Some(cell_layout_reorder::<T>);
327 iface.get_cells = Some(cell_layout_get_cells::<T>);
328 iface.get_area = Some(cell_layout_get_area::<T>);
329 }
330}
331
332unsafe extern "C" fn cell_layout_pack_start<T: CellLayoutImpl>(
333 cell_layout_ptr: *mut ffi::GtkCellLayout,
334 cell_ptr: *mut ffi::GtkCellRenderer,
335 expand: glib::ffi::gboolean,
336) {
337 assert!(!cell_layout_ptr.is_null());
338 assert!(!cell_ptr.is_null());
339
340 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
341 let imp = instance.imp();
342 unsafe {
343 imp.pack_start(&from_glib_borrow(cell_ptr), from_glib(expand));
344 }
345}
346
347unsafe extern "C" fn cell_layout_pack_end<T: CellLayoutImpl>(
348 cell_layout_ptr: *mut ffi::GtkCellLayout,
349 cell_ptr: *mut ffi::GtkCellRenderer,
350 expand: glib::ffi::gboolean,
351) {
352 assert!(!cell_layout_ptr.is_null());
353 assert!(!cell_ptr.is_null());
354
355 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
356 let imp = instance.imp();
357 unsafe {
358 imp.pack_end(&from_glib_borrow(cell_ptr), from_glib(expand));
359 }
360}
361
362unsafe extern "C" fn cell_layout_clear<T: CellLayoutImpl>(
363 cell_layout_ptr: *mut ffi::GtkCellLayout,
364) {
365 assert!(!cell_layout_ptr.is_null());
366
367 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
368 let imp = instance.imp();
369 imp.clear();
370}
371
372unsafe extern "C" fn cell_layout_add_attribute<T: CellLayoutImpl>(
373 cell_layout_ptr: *mut ffi::GtkCellLayout,
374 cell_ptr: *mut ffi::GtkCellRenderer,
375 attribute_ptr: *const glib::ffi::gchar,
376 column: i32,
377) {
378 assert!(!cell_layout_ptr.is_null());
379 assert!(!cell_ptr.is_null());
380 assert!(!attribute_ptr.is_null());
381
382 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
383 let imp = instance.imp();
384 unsafe {
385 let attribute = CStr::from_ptr(attribute_ptr).to_str().unwrap();
386 imp.add_attribute(&from_glib_borrow(cell_ptr), attribute, column);
387 }
388}
389
390unsafe extern "C" fn cell_layout_set_cell_data_func<T: CellLayoutImpl>(
391 cell_layout_ptr: *mut ffi::GtkCellLayout,
392 cell_ptr: *mut ffi::GtkCellRenderer,
393 func_ptr: ffi::GtkCellLayoutDataFunc,
394 func_data_ptr: glib::ffi::gpointer,
395 destroy_ptr: glib::ffi::GDestroyNotify,
396) {
397 assert!(!cell_layout_ptr.is_null());
398 assert!(!cell_ptr.is_null());
399
400 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
401 let imp = instance.imp();
402
403 let cell = unsafe { from_glib_borrow(cell_ptr) };
404 let cell_data_func = func_ptr.is_some().then(|| CellDataFunc {
405 func: func_ptr,
406 func_data: func_data_ptr,
407 destroy: destroy_ptr,
408 });
409
410 imp.set_cell_data_func(&cell, cell_data_func);
411}
412
413unsafe extern "C" fn cell_layout_clear_attributes<T: CellLayoutImpl>(
414 cell_layout_ptr: *mut ffi::GtkCellLayout,
415 cell_ptr: *mut ffi::GtkCellRenderer,
416) {
417 assert!(!cell_layout_ptr.is_null());
418 assert!(!cell_ptr.is_null());
419
420 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
421 let imp = instance.imp();
422 unsafe {
423 imp.clear_attributes(&from_glib_borrow(cell_ptr));
424 }
425}
426
427unsafe extern "C" fn cell_layout_reorder<T: CellLayoutImpl>(
428 cell_layout_ptr: *mut ffi::GtkCellLayout,
429 cell_ptr: *mut ffi::GtkCellRenderer,
430 position: i32,
431) {
432 assert!(!cell_layout_ptr.is_null());
433 assert!(!cell_ptr.is_null());
434
435 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
436 let imp = instance.imp();
437 unsafe {
438 imp.reorder(&from_glib_borrow(cell_ptr), position);
439 }
440}
441
442unsafe extern "C" fn cell_layout_get_cells<T: CellLayoutImpl>(
443 cell_layout_ptr: *mut ffi::GtkCellLayout,
444) -> *mut glib::ffi::GList {
445 assert!(!cell_layout_ptr.is_null());
446
447 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
448 let imp = instance.imp();
449 imp.cells().to_glib_container().0
450}
451
452unsafe extern "C" fn cell_layout_get_area<T: CellLayoutImpl>(
453 cell_layout_ptr: *mut ffi::GtkCellLayout,
454) -> *mut ffi::GtkCellArea {
455 assert!(!cell_layout_ptr.is_null());
456
457 let instance = unsafe { &*(cell_layout_ptr as *mut T::Instance) };
458 let imp = instance.imp();
459 imp.area().to_glib_none().0
460}