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