libpanel/
layered_settings.rs

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