1use std::sync::OnceLock;
7
8use glib::{translate::*, Quark};
9
10use crate::{
11 ffi, prelude::*, subclass::prelude::*, CellArea, CellLayout, CellRenderer, TreeIter, TreeModel,
12};
13
14#[derive(Debug)]
15pub struct CellLayoutDataCallback {
16 callback: ffi::GtkCellLayoutDataFunc,
17 user_data: glib::ffi::gpointer,
18 destroy_notify: glib::ffi::GDestroyNotify,
19}
20
21impl CellLayoutDataCallback {
22 pub fn call<C: IsA<CellLayout>, R: IsA<CellRenderer>, M: IsA<TreeModel>>(
23 &self,
24 cell_layout: &C,
25 cell_renderer: &R,
26 model: &M,
27 iter: &TreeIter,
28 ) {
29 unsafe {
30 if let Some(callback) = self.callback {
31 callback(
32 cell_layout.as_ref().to_glib_none().0,
33 cell_renderer.as_ref().to_glib_none().0,
34 model.as_ref().to_glib_none().0,
35 mut_override(iter.to_glib_none().0),
36 self.user_data,
37 );
38 }
39 }
40 }
41}
42
43impl Drop for CellLayoutDataCallback {
44 #[inline]
45 fn drop(&mut self) {
46 unsafe {
47 if let Some(destroy_notify) = self.destroy_notify {
48 destroy_notify(self.user_data);
49 }
50 }
51 }
52}
53
54#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
55#[allow(deprecated)]
56pub trait CellLayoutImpl: ObjectImpl {
57 fn add_attribute<R: IsA<CellRenderer>>(&self, cell: &R, attribute: &str, column: i32) {
58 self.parent_add_attribute(cell, attribute, column)
59 }
60
61 fn clear_attributes<R: IsA<CellRenderer>>(&self, cell: &R) {
62 self.parent_clear_attributes(cell)
63 }
64
65 fn cells(&self) -> Vec<CellRenderer> {
66 self.parent_cells()
67 }
68
69 fn set_cell_data_func<R: IsA<CellRenderer>>(
70 &self,
71
72 cell: &R,
73 callback: Option<CellLayoutDataCallback>,
74 ) {
75 self.parent_set_cell_data_func(cell, callback)
76 }
77
78 fn reorder<R: IsA<CellRenderer>>(&self, cell: &R, position: i32) {
79 self.parent_reorder(cell, position)
80 }
81
82 fn clear(&self) {
83 self.parent_clear()
84 }
85
86 fn pack_start<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
87 self.parent_pack_start(cell, expand)
88 }
89
90 fn pack_end<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
91 self.parent_pack_end(cell, expand)
92 }
93
94 fn area(&self) -> Option<CellArea> {
95 self.parent_area()
96 }
97}
98
99mod sealed {
100 pub trait Sealed {}
101 impl<T: super::CellLayoutImplExt> Sealed for T {}
102}
103
104#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
105#[allow(deprecated)]
106pub trait CellLayoutImplExt: sealed::Sealed + ObjectSubclass {
107 fn parent_add_attribute<R: IsA<CellRenderer>>(&self, cell: &R, attribute: &str, column: i32) {
108 unsafe {
109 let type_data = Self::type_data();
110 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
111 as *const ffi::GtkCellLayoutIface;
112
113 if let Some(f) = (*parent_iface).add_attribute {
114 f(
115 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
116 cell.as_ref().to_glib_none().0,
117 attribute.to_glib_none().0,
118 column,
119 );
120 }
121 }
122 }
123
124 fn parent_clear_attributes<R: IsA<CellRenderer>>(&self, cell: &R) {
125 unsafe {
126 let type_data = Self::type_data();
127 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
128 as *const ffi::GtkCellLayoutIface;
129
130 if let Some(f) = (*parent_iface).clear_attributes {
131 f(
132 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
133 cell.as_ref().to_glib_none().0,
134 );
135 }
136 }
137 }
138
139 fn parent_cells(&self) -> Vec<CellRenderer> {
140 unsafe {
141 let type_data = Self::type_data();
142 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
143 as *const ffi::GtkCellLayoutIface;
144
145 let f = (*parent_iface)
146 .get_cells
147 .as_ref()
148 .expect("no parent \"get_cells\" implementation");
149
150 let cells = f(self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0);
151 FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(cells)
152 }
153 }
154
155 fn parent_set_cell_data_func<R: IsA<CellRenderer>>(
156 &self,
157
158 cell: &R,
159 callback: Option<CellLayoutDataCallback>,
160 ) {
161 unsafe {
162 let type_data = Self::type_data();
163 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
164 as *const ffi::GtkCellLayoutIface;
165
166 let f = (*parent_iface)
167 .set_cell_data_func
168 .as_ref()
169 .expect("no parent \"set_cell_data_func\" implementation");
170
171 if let Some(data_cb) = callback {
172 f(
173 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
174 cell.as_ref().to_glib_none().0,
175 data_cb.callback,
176 data_cb.user_data,
177 data_cb.destroy_notify,
178 );
179 } else {
180 f(
181 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
182 cell.as_ref().to_glib_none().0,
183 None,
184 std::ptr::null_mut(),
185 None,
186 );
187 }
188 }
189 }
190
191 fn parent_reorder<R: IsA<CellRenderer>>(&self, cell: &R, position: i32) {
192 {
193 unsafe {
194 let type_data = Self::type_data();
195 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
196 as *const ffi::GtkCellLayoutIface;
197
198 if let Some(f) = (*parent_iface).reorder {
199 f(
200 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
201 cell.as_ref().to_glib_none().0,
202 position,
203 );
204 }
205 }
206 }
207 }
208
209 fn parent_clear(&self) {
210 unsafe {
211 let type_data = Self::type_data();
212 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
213 as *const ffi::GtkCellLayoutIface;
214
215 if let Some(f) = (*parent_iface).clear {
216 f(self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0);
217 }
218 }
219 }
220
221 fn parent_pack_start<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
222 unsafe {
223 let type_data = Self::type_data();
224 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
225 as *const ffi::GtkCellLayoutIface;
226
227 if let Some(f) = (*parent_iface).pack_start {
228 f(
229 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
230 cell.as_ref().to_glib_none().0,
231 expand.into_glib(),
232 );
233 }
234 }
235 }
236
237 fn parent_pack_end<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
238 unsafe {
239 let type_data = Self::type_data();
240 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
241 as *const ffi::GtkCellLayoutIface;
242
243 if let Some(f) = (*parent_iface).pack_end {
244 f(
245 self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
246 cell.as_ref().to_glib_none().0,
247 expand.into_glib(),
248 );
249 }
250 }
251 }
252
253 fn parent_area(&self) -> Option<CellArea> {
254 unsafe {
255 let type_data = Self::type_data();
256 let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
257 as *const ffi::GtkCellLayoutIface;
258
259 (*parent_iface).get_area.map(|f| {
260 from_glib_none(f(self
261 .obj()
262 .unsafe_cast_ref::<CellLayout>()
263 .to_glib_none()
264 .0))
265 })
266 }
267 }
268}
269
270impl<T: CellLayoutImpl> CellLayoutImplExt for T {}
271
272unsafe impl<T: CellLayoutImpl> IsImplementable<T> for CellLayout {
273 fn interface_init(iface: &mut glib::Interface<Self>) {
274 let iface = iface.as_mut();
275
276 assert_initialized_main_thread!();
277
278 iface.get_area = Some(cell_layout_get_area::<T>);
279 iface.pack_start = Some(cell_layout_pack_start::<T>);
280 iface.pack_end = Some(cell_layout_pack_end::<T>);
281 iface.clear = Some(cell_layout_clear::<T>);
282 iface.reorder = Some(cell_layout_reorder::<T>);
283 iface.add_attribute = Some(cell_layout_add_attribute::<T>);
284 iface.clear_attributes = Some(cell_layout_clear_attributes::<T>);
285 iface.set_cell_data_func = Some(cell_layout_set_cell_data_func::<T>);
286 iface.get_cells = Some(cell_layout_get_cells::<T>);
287 }
288}
289
290unsafe extern "C" fn cell_layout_get_area<T: CellLayoutImpl>(
291 cell_layout: *mut ffi::GtkCellLayout,
292) -> *mut ffi::GtkCellArea {
293 let instance = &*(cell_layout as *mut T::Instance);
294 let imp = instance.imp();
295
296 imp.area().into_glib_ptr()
297}
298
299unsafe extern "C" fn cell_layout_pack_start<T: CellLayoutImpl>(
300 cell_layout: *mut ffi::GtkCellLayout,
301 cellptr: *mut ffi::GtkCellRenderer,
302 expand: glib::ffi::gboolean,
303) {
304 let instance = &*(cell_layout as *mut T::Instance);
305 let imp = instance.imp();
306 let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
307
308 imp.pack_start(&*cell, from_glib(expand))
309}
310
311unsafe extern "C" fn cell_layout_pack_end<T: CellLayoutImpl>(
312 cell_layout: *mut ffi::GtkCellLayout,
313 cellptr: *mut ffi::GtkCellRenderer,
314 expand: glib::ffi::gboolean,
315) {
316 let instance = &*(cell_layout as *mut T::Instance);
317 let imp = instance.imp();
318 let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
319
320 imp.pack_end(&*cell, from_glib(expand))
321}
322
323unsafe extern "C" fn cell_layout_clear<T: CellLayoutImpl>(cell_layout: *mut ffi::GtkCellLayout) {
324 let instance = &*(cell_layout as *mut T::Instance);
325 let imp = instance.imp();
326
327 imp.clear()
328}
329
330unsafe extern "C" fn cell_layout_reorder<T: CellLayoutImpl>(
331 cell_layout: *mut ffi::GtkCellLayout,
332 cellptr: *mut ffi::GtkCellRenderer,
333 position: i32,
334) {
335 let instance = &*(cell_layout as *mut T::Instance);
336 let imp = instance.imp();
337 let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
338
339 imp.reorder(&*cell, position)
340}
341
342unsafe extern "C" fn cell_layout_add_attribute<T: CellLayoutImpl>(
343 cell_layout: *mut ffi::GtkCellLayout,
344 cellptr: *mut ffi::GtkCellRenderer,
345 attributeptr: *const libc::c_char,
346 column: i32,
347) {
348 let instance = &*(cell_layout as *mut T::Instance);
349 let imp = instance.imp();
350 let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
351 let attribute: Borrowed<glib::GString> = from_glib_borrow(attributeptr);
352
353 imp.add_attribute(&*cell, &attribute, column)
354}
355
356unsafe extern "C" fn cell_layout_clear_attributes<T: CellLayoutImpl>(
357 cell_layout: *mut ffi::GtkCellLayout,
358 cellptr: *mut ffi::GtkCellRenderer,
359) {
360 let instance = &*(cell_layout as *mut T::Instance);
361 let imp = instance.imp();
362 let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
363
364 imp.clear_attributes(&*cell)
365}
366
367unsafe extern "C" fn cell_layout_set_cell_data_func<T: CellLayoutImpl>(
368 cell_layout: *mut ffi::GtkCellLayout,
369 cellptr: *mut ffi::GtkCellRenderer,
370 callback: ffi::GtkCellLayoutDataFunc,
371 user_data: glib::ffi::gpointer,
372 destroy_notify: glib::ffi::GDestroyNotify,
373) {
374 let instance = &*(cell_layout as *mut T::Instance);
375 let imp = instance.imp();
376
377 let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
378
379 let callback = if callback.is_none() {
380 None
381 } else {
382 Some(CellLayoutDataCallback {
383 callback,
384 user_data,
385 destroy_notify,
386 })
387 };
388
389 imp.set_cell_data_func(&*cell, callback)
390}
391
392unsafe extern "C" fn cell_layout_get_cells<T: CellLayoutImpl>(
393 cell_layout: *mut ffi::GtkCellLayout,
394) -> *mut glib::ffi::GList {
395 let instance = &*(cell_layout as *mut T::Instance);
396 let imp = instance.imp();
397
398 let cells = imp.cells();
399
400 static QUARK: OnceLock<Quark> = OnceLock::new();
401 let quark = *QUARK.get_or_init(|| Quark::from_str("gtk-rs-subclass-cell-layout-get-cells"));
402
403 imp.obj().set_qdata(quark, cells.clone());
406 cells.to_glib_container().0
407}