Skip to main content

gtk4/subclass/
font_chooser.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for implementing the [`FontChooser`] interface.
5use std::sync::OnceLock;
6
7use glib::{GString, Quark, translate::*};
8use pango::{FontFace, FontFamily, FontMap};
9
10use super::PtrHolder;
11use crate::{FontChooser, ffi, prelude::*, subclass::prelude::*};
12
13#[derive(Debug)]
14pub struct FilterCallback {
15    filter_func: ffi::GtkFontFilterFunc,
16    user_data: glib::ffi::gpointer,
17    destroy_notify: glib::ffi::GDestroyNotify,
18}
19
20impl FilterCallback {
21    // true if the font should be displayed
22    pub fn call(&self, font_family: &FontFamily, font_face: &FontFace) -> bool {
23        unsafe {
24            if let Some(filter_func) = self.filter_func {
25                from_glib(filter_func(
26                    font_family.to_glib_none().0,
27                    font_face.to_glib_none().0,
28                    self.user_data,
29                ))
30            } else {
31                // show the font if the filter_func was not set
32                true
33            }
34        }
35    }
36}
37
38impl Drop for FilterCallback {
39    #[inline]
40    fn drop(&mut self) {
41        unsafe {
42            if let Some(destroy_notify) = self.destroy_notify {
43                destroy_notify(self.user_data)
44            }
45        }
46    }
47}
48
49#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
50#[allow(deprecated)]
51pub trait FontChooserImpl: ObjectImpl + ObjectSubclass<Type: IsA<FontChooser>> {
52    fn font_family(&self) -> Option<FontFamily> {
53        self.parent_font_family()
54    }
55
56    fn font_face(&self) -> Option<FontFace> {
57        self.parent_font_face()
58    }
59
60    fn font_size(&self) -> i32 {
61        self.parent_font_size()
62    }
63
64    fn set_filter_func(&self, callback: Option<FilterCallback>) {
65        self.parent_set_filter_func(callback)
66    }
67
68    fn set_font_map<P: IsA<FontMap>>(&self, font_map: Option<&P>) {
69        self.parent_set_font_map(font_map)
70    }
71
72    fn font_map(&self) -> Option<FontMap> {
73        self.parent_font_map()
74    }
75
76    fn font_activated(&self, font_name: &str) {
77        self.parent_font_activated(font_name)
78    }
79}
80
81#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
82#[allow(deprecated)]
83pub trait FontChooserImplExt: FontChooserImpl {
84    fn parent_font_family(&self) -> Option<FontFamily> {
85        unsafe {
86            let type_data = Self::type_data();
87            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
88                as *const ffi::GtkFontChooserIface;
89            let f = (*parent_iface)
90                .get_font_family
91                .expect("no parent \"get_font_family\" implementation");
92
93            from_glib_none(f(self
94                .obj()
95                .unsafe_cast_ref::<FontChooser>()
96                .to_glib_none()
97                .0))
98        }
99    }
100
101    fn parent_font_face(&self) -> Option<FontFace> {
102        unsafe {
103            let type_data = Self::type_data();
104            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
105                as *const ffi::GtkFontChooserIface;
106
107            let f = (*parent_iface)
108                .get_font_face
109                .expect("no parent \"get_font_face\" implementation");
110
111            from_glib_none(f(self
112                .obj()
113                .unsafe_cast_ref::<FontChooser>()
114                .to_glib_none()
115                .0))
116        }
117    }
118
119    fn parent_font_size(&self) -> i32 {
120        unsafe {
121            let type_data = Self::type_data();
122            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
123                as *const ffi::GtkFontChooserIface;
124
125            if let Some(f) = (*parent_iface).get_font_size {
126                f(self.obj().unsafe_cast_ref::<FontChooser>().to_glib_none().0)
127            } else {
128                // No font size is selected
129                -1
130            }
131        }
132    }
133
134    fn parent_set_filter_func(&self, callback: Option<FilterCallback>) {
135        unsafe {
136            let type_data = Self::type_data();
137            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
138                as *const ffi::GtkFontChooserIface;
139
140            if let Some(f) = (*parent_iface).set_filter_func {
141                if let Some(filter_callback) = callback {
142                    f(
143                        self.obj().unsafe_cast_ref::<FontChooser>().to_glib_none().0,
144                        filter_callback.filter_func,
145                        filter_callback.user_data,
146                        filter_callback.destroy_notify,
147                    )
148                } else {
149                    f(
150                        self.obj().unsafe_cast_ref::<FontChooser>().to_glib_none().0,
151                        None,
152                        std::ptr::null_mut(),
153                        None,
154                    )
155                }
156            }
157        }
158    }
159
160    fn parent_set_font_map<P: IsA<FontMap>>(&self, font_map: Option<&P>) {
161        unsafe {
162            let type_data = Self::type_data();
163            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
164                as *const ffi::GtkFontChooserIface;
165
166            let f = (*parent_iface)
167                .set_font_map
168                .expect("no parent \"set_font_map\" implementation");
169            f(
170                self.obj().unsafe_cast_ref::<FontChooser>().to_glib_none().0,
171                font_map.map(|fm| fm.as_ref()).to_glib_none().0,
172            );
173        }
174    }
175
176    fn parent_font_map(&self) -> Option<FontMap> {
177        unsafe {
178            let type_data = Self::type_data();
179            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
180                as *const ffi::GtkFontChooserIface;
181
182            let f = (*parent_iface)
183                .get_font_map
184                .expect("no parent \"get_font_map\" implementation");
185
186            from_glib_none(f(self
187                .obj()
188                .unsafe_cast_ref::<FontChooser>()
189                .to_glib_none()
190                .0))
191        }
192    }
193
194    fn parent_font_activated(&self, font_name: &str) {
195        unsafe {
196            let type_data = Self::type_data();
197            let parent_iface = type_data.as_ref().parent_interface::<FontChooser>()
198                as *const ffi::GtkFontChooserIface;
199            if let Some(f) = (*parent_iface).font_activated {
200                f(
201                    self.obj().unsafe_cast_ref::<FontChooser>().to_glib_none().0,
202                    font_name.to_glib_none().0,
203                );
204            }
205        }
206    }
207}
208
209impl<T: FontChooserImpl> FontChooserImplExt for T {}
210
211unsafe impl<T: FontChooserImpl> IsImplementable<T> for FontChooser {
212    fn interface_init(iface: &mut glib::Interface<Self>) {
213        let iface = iface.as_mut();
214
215        assert_initialized_main_thread!();
216
217        iface.get_font_family = Some(font_chooser_get_font_family::<T>);
218        iface.get_font_face = Some(font_chooser_get_font_face::<T>);
219        iface.get_font_size = Some(font_chooser_get_font_size::<T>);
220        iface.font_activated = Some(font_chooser_font_activated::<T>);
221        iface.set_font_map = Some(font_chooser_set_font_map::<T>);
222        iface.get_font_map = Some(font_chooser_get_font_map::<T>);
223        iface.set_filter_func = Some(font_chooser_set_filter_func::<T>);
224    }
225}
226
227unsafe extern "C" fn font_chooser_get_font_family<T: FontChooserImpl>(
228    font_chooser: *mut ffi::GtkFontChooser,
229) -> *mut pango::ffi::PangoFontFamily {
230    unsafe {
231        let instance = &*(font_chooser as *mut T::Instance);
232        let imp = instance.imp();
233
234        let ret = imp.font_family();
235        if let Some(font_family) = ret {
236            let font_family = font_family.into_glib_ptr();
237
238            static QUARK: OnceLock<Quark> = OnceLock::new();
239            let quark =
240                *QUARK.get_or_init(|| Quark::from_str("gtk4-rs-subclass-font-chooser-font-family"));
241
242            imp.obj().set_qdata(
243                quark,
244                PtrHolder(font_family, |ptr| {
245                    glib::gobject_ffi::g_object_unref(ptr as *mut _)
246                }),
247            );
248            font_family
249        } else {
250            std::ptr::null_mut()
251        }
252    }
253}
254
255unsafe extern "C" fn font_chooser_get_font_face<T: FontChooserImpl>(
256    font_chooser: *mut ffi::GtkFontChooser,
257) -> *mut pango::ffi::PangoFontFace {
258    unsafe {
259        let instance = &*(font_chooser as *mut T::Instance);
260        let imp = instance.imp();
261
262        let ret = imp.font_face();
263        if let Some(font_face) = ret {
264            let font_face = font_face.into_glib_ptr();
265            static QUARK: OnceLock<Quark> = OnceLock::new();
266            let quark =
267                *QUARK.get_or_init(|| Quark::from_str("gtk4-rs-subclass-font-chooser-font-face"));
268            imp.obj().set_qdata(
269                quark,
270                PtrHolder(font_face, |ptr| {
271                    glib::gobject_ffi::g_object_unref(ptr as *mut _);
272                }),
273            );
274            font_face
275        } else {
276            std::ptr::null_mut()
277        }
278    }
279}
280
281unsafe extern "C" fn font_chooser_get_font_size<T: FontChooserImpl>(
282    font_chooser: *mut ffi::GtkFontChooser,
283) -> i32 {
284    unsafe {
285        let instance = &*(font_chooser as *mut T::Instance);
286        let imp = instance.imp();
287
288        imp.font_size()
289    }
290}
291
292unsafe extern "C" fn font_chooser_font_activated<T: FontChooserImpl>(
293    font_chooser: *mut ffi::GtkFontChooser,
294    font_nameptr: *const libc::c_char,
295) {
296    unsafe {
297        let instance = &*(font_chooser as *mut T::Instance);
298        let imp = instance.imp();
299        let font_name: Borrowed<GString> = from_glib_borrow(font_nameptr);
300
301        imp.font_activated(&font_name)
302    }
303}
304
305unsafe extern "C" fn font_chooser_set_font_map<T: FontChooserImpl>(
306    font_chooser: *mut ffi::GtkFontChooser,
307    font_mapptr: *mut pango::ffi::PangoFontMap,
308) {
309    unsafe {
310        let instance = &*(font_chooser as *mut T::Instance);
311        let imp = instance.imp();
312        let font_map: Borrowed<Option<FontMap>> = from_glib_borrow(font_mapptr);
313
314        imp.set_font_map(font_map.as_ref().as_ref())
315    }
316}
317
318unsafe extern "C" fn font_chooser_get_font_map<T: FontChooserImpl>(
319    font_chooser: *mut ffi::GtkFontChooser,
320) -> *mut pango::ffi::PangoFontMap {
321    unsafe {
322        let instance = &*(font_chooser as *mut T::Instance);
323        let imp = instance.imp();
324
325        imp.font_map().into_glib_ptr()
326    }
327}
328
329unsafe extern "C" fn font_chooser_set_filter_func<T: FontChooserImpl>(
330    font_chooser: *mut ffi::GtkFontChooser,
331    filter_func: ffi::GtkFontFilterFunc,
332    user_data: glib::ffi::gpointer,
333    destroy_notify: glib::ffi::GDestroyNotify,
334) {
335    unsafe {
336        let instance = &*(font_chooser as *mut T::Instance);
337        let imp = instance.imp();
338
339        let callback = if filter_func.is_some() {
340            None
341        } else {
342            Some(FilterCallback {
343                filter_func,
344                user_data,
345                destroy_notify,
346            })
347        };
348
349        imp.set_filter_func(callback);
350    }
351}