libpanel/
settings.rs

1use crate::{prelude::*, Settings};
2use glib::translate::*;
3use std::ffi::c_void;
4
5impl Settings {
6    #[doc(alias = "panel_settings_bind")]
7    #[doc(alias = "panel_settings_bind_with_mapping")]
8    pub fn bind<'a, P: IsA<glib::Object>>(
9        &'a self,
10        key: &'a str,
11        object: &'a P,
12        property: &'a str,
13    ) -> BindingBuilder<'a> {
14        BindingBuilder {
15            settings: self.upcast_ref(),
16            key,
17            object: object.upcast_ref(),
18            property,
19            flags: gio::SettingsBindFlags::DEFAULT,
20            get_mapping: None,
21            set_mapping: None,
22        }
23    }
24
25    #[doc(alias = "panel_settings_get_schema_id")]
26    #[doc(alias = "get_schema_id")]
27    pub fn schema_id(&self) -> &glib::GStr {
28        unsafe { from_glib_none(ffi::panel_settings_get_schema_id(self.to_glib_none().0)) }
29    }
30}
31
32#[must_use = "The builder must be built to be used"]
33pub struct BindingBuilder<'a> {
34    settings: &'a Settings,
35    key: &'a str,
36    object: &'a glib::Object,
37    property: &'a str,
38    flags: gio::SettingsBindFlags,
39    #[allow(clippy::type_complexity)]
40    get_mapping: Option<Box<dyn Fn(&glib::Variant, glib::Type) -> Option<glib::Value>>>,
41    #[allow(clippy::type_complexity)]
42    set_mapping: Option<Box<dyn Fn(&glib::Value, glib::VariantType) -> Option<glib::Variant>>>,
43}
44
45impl<'a> BindingBuilder<'a> {
46    pub fn flags(mut self, flags: gio::SettingsBindFlags) -> Self {
47        self.flags = flags;
48        self
49    }
50
51    // rustdoc-stripper-ignore-next
52    /// Set the binding flags to [`GET`][gio::SettingsBindFlags::GET].
53    pub fn get(mut self) -> Self {
54        self.flags |= gio::SettingsBindFlags::GET;
55        self
56    }
57
58    // rustdoc-stripper-ignore-next
59    /// Set the binding flags to [`SET`][gio::SettingsBindFlags::SET].
60    pub fn set(mut self) -> Self {
61        self.flags |= gio::SettingsBindFlags::SET;
62        self
63    }
64
65    // rustdoc-stripper-ignore-next
66    /// Unsets the default [`GET`][gio::SettingsBindFlags::GET] flag.
67    pub fn set_only(mut self) -> Self {
68        self.flags = (self.flags - gio::SettingsBindFlags::GET) | gio::SettingsBindFlags::SET;
69        self
70    }
71
72    // rustdoc-stripper-ignore-next
73    /// Unsets the default [`SET`][gio::SettingsBindFlags::SET] flag.
74    pub fn get_only(mut self) -> Self {
75        self.flags = (self.flags - gio::SettingsBindFlags::SET) | gio::SettingsBindFlags::GET;
76        self
77    }
78
79    // rustdoc-stripper-ignore-next
80    /// Set the binding flags to [`NO_SENSITIVITY`][gio::SettingsBindFlags::NO_SENSITIVITY].
81    pub fn no_sensitivity(mut self) -> Self {
82        self.flags |= gio::SettingsBindFlags::NO_SENSITIVITY;
83        self
84    }
85
86    // rustdoc-stripper-ignore-next
87    /// Set the binding flags to [`GET_NO_CHANGES`][gio::SettingsBindFlags::GET_NO_CHANGES].
88    pub fn get_no_changes(mut self) -> Self {
89        self.flags |= gio::SettingsBindFlags::GET_NO_CHANGES;
90        self
91    }
92
93    // rustdoc-stripper-ignore-next
94    /// Set the binding flags to [`INVERT_BOOLEAN`][gio::SettingsBindFlags::INVERT_BOOLEAN].
95    pub fn invert_boolean(mut self) -> Self {
96        self.flags |= gio::SettingsBindFlags::INVERT_BOOLEAN;
97        self
98    }
99
100    #[doc(alias = "get_mapping")]
101    pub fn mapping<F: Fn(&glib::Variant, glib::Type) -> Option<glib::Value> + 'static>(
102        mut self,
103        f: F,
104    ) -> Self {
105        self.get_mapping = Some(Box::new(f));
106        self
107    }
108
109    pub fn set_mapping<
110        F: Fn(&glib::Value, glib::VariantType) -> Option<glib::Variant> + 'static,
111    >(
112        mut self,
113        f: F,
114    ) -> Self {
115        self.set_mapping = Some(Box::new(f));
116        self
117    }
118
119    pub fn build(self) {
120        type Mappings = (
121            Option<Box<dyn Fn(&glib::Variant, glib::Type) -> Option<glib::Value>>>,
122            Option<Box<dyn Fn(&glib::Value, glib::VariantType) -> Option<glib::Variant>>>,
123        );
124        unsafe extern "C" fn bind_with_mapping_get_trampoline(
125            value: *mut glib::gobject_ffi::GValue,
126            variant: *mut glib::ffi::GVariant,
127            user_data: glib::ffi::gpointer,
128        ) -> glib::ffi::gboolean {
129            let user_data = &*(user_data as *const Mappings);
130            let f = user_data.0.as_ref().unwrap();
131            let value = &mut *(value as *mut glib::Value);
132            if let Some(v) = f(&from_glib_borrow(variant), value.type_()) {
133                *value = v;
134                true
135            } else {
136                false
137            }
138            .into_glib()
139        }
140        unsafe extern "C" fn bind_with_mapping_set_trampoline(
141            value: *const glib::gobject_ffi::GValue,
142            variant_type: *const glib::ffi::GVariantType,
143            user_data: glib::ffi::gpointer,
144        ) -> *mut glib::ffi::GVariant {
145            let user_data = &*(user_data as *const Mappings);
146            let f = user_data.1.as_ref().unwrap();
147            let value = &*(value as *const glib::Value);
148            f(value, from_glib_none(variant_type)).into_glib_ptr()
149        }
150        unsafe extern "C" fn destroy_closure(ptr: *mut c_void) {
151            let _ = Box::<Mappings>::from_raw(ptr as *mut _);
152        }
153
154        if self.get_mapping.is_none() && self.set_mapping.is_none() {
155            unsafe {
156                ffi::panel_settings_bind(
157                    self.settings.to_glib_none().0,
158                    self.key.to_glib_none().0,
159                    ToGlibPtr::<*mut glib::gobject_ffi::GObject>::to_glib_none(&self.object).0
160                        as *mut _,
161                    self.property.to_glib_none().0,
162                    self.flags.into_glib(),
163                );
164            }
165        } else {
166            let get_trampoline: Option<unsafe extern "C" fn(_, _, _) -> _> =
167                if self.get_mapping.is_none() {
168                    None
169                } else {
170                    Some(bind_with_mapping_get_trampoline)
171                };
172            let set_trampoline: Option<unsafe extern "C" fn(_, _, _) -> _> =
173                if self.set_mapping.is_none() {
174                    None
175                } else {
176                    Some(bind_with_mapping_set_trampoline)
177                };
178            let mappings: Mappings = (self.get_mapping, self.set_mapping);
179            unsafe {
180                ffi::panel_settings_bind_with_mapping(
181                    self.settings.to_glib_none().0,
182                    self.key.to_glib_none().0,
183                    ToGlibPtr::<*mut glib::gobject_ffi::GObject>::to_glib_none(&self.object).0
184                        as *mut _,
185                    self.property.to_glib_none().0,
186                    self.flags.into_glib(),
187                    get_trampoline,
188                    set_trampoline,
189                    Box::into_raw(Box::new(mappings)) as *mut c_void,
190                    Some(destroy_closure),
191                )
192            }
193        }
194    }
195}