Skip to main content

gtk/
builder.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{Builder, Widget};
4use glib::prelude::*;
5use glib::translate::*;
6use glib::GString;
7use glib::Object;
8use std::path::Path;
9use std::ptr;
10
11impl Builder {
12    #[doc(alias = "gtk_builder_new_from_file")]
13    pub fn from_file<T: AsRef<Path>>(file_path: T) -> Builder {
14        assert_initialized_main_thread!();
15        unsafe {
16            from_glib_full(ffi::gtk_builder_new_from_file(
17                file_path.as_ref().to_glib_none().0,
18            ))
19        }
20    }
21}
22
23mod sealed {
24    pub trait Sealed {}
25    impl<T: glib::IsA<crate::Builder>> Sealed for T {}
26}
27
28pub trait BuilderExtManual: IsA<Builder> + sealed::Sealed + 'static {
29    #[doc(alias = "gtk_builder_get_object")]
30    #[doc(alias = "get_object")]
31    fn object<T: IsA<Object>>(&self, name: &str) -> Option<T> {
32        unsafe {
33            Option::<Object>::from_glib_none(ffi::gtk_builder_get_object(
34                self.upcast_ref().to_glib_none().0,
35                name.to_glib_none().0,
36            ))
37            .and_then(|obj| obj.dynamic_cast::<T>().ok())
38        }
39    }
40
41    #[doc(alias = "gtk_builder_add_from_file")]
42    fn add_from_file<T: AsRef<Path>>(&self, file_path: T) -> Result<(), glib::Error> {
43        unsafe {
44            let mut error = ::std::ptr::null_mut();
45            let exit_code = ffi::gtk_builder_add_from_file(
46                self.upcast_ref().to_glib_none().0,
47                file_path.as_ref().to_glib_none().0,
48                &mut error,
49            );
50            assert_eq!(exit_code == 0, !error.is_null());
51            if error.is_null() {
52                Ok(())
53            } else {
54                Err(from_glib_full(error))
55            }
56        }
57    }
58    /// Parses a resource file containing a [GtkBuilder UI definition][BUILDER-UI]
59    /// and merges it with the current contents of `self`.
60    ///
61    /// Most users will probably want to use [`Builder::from_resource()`][crate::Builder::from_resource()].
62    ///
63    /// If an error occurs, 0 will be returned and `error` will be assigned a
64    /// [`glib::Error`][crate::glib::Error] from the `GTK_BUILDER_ERROR`, `G_MARKUP_ERROR` or `G_RESOURCE_ERROR`
65    /// domain.
66    ///
67    /// It’s not really reasonable to attempt to handle failures of this
68    /// call. The only reasonable thing to do when an error is detected is
69    /// to call `g_error()`.
70    /// ## `resource_path`
71    /// the path of the resource file to parse
72    ///
73    /// # Returns
74    ///
75    /// A positive value on success, 0 if an error occurred
76    #[doc(alias = "gtk_builder_add_from_resource")]
77    fn add_from_resource(&self, resource_path: &str) -> Result<(), glib::Error> {
78        unsafe {
79            let mut error = ptr::null_mut();
80            let exit_code = ffi::gtk_builder_add_from_resource(
81                self.as_ref().to_glib_none().0,
82                resource_path.to_glib_none().0,
83                &mut error,
84            );
85            assert_eq!(exit_code == 0, !error.is_null());
86            if error.is_null() {
87                Ok(())
88            } else {
89                Err(from_glib_full(error))
90            }
91        }
92    }
93    /// Parses a string containing a [GtkBuilder UI definition][BUILDER-UI]
94    /// and merges it with the current contents of `self`.
95    ///
96    /// Most users will probably want to use [`Builder::from_string()`][crate::Builder::from_string()].
97    ///
98    /// Upon errors 0 will be returned and `error` will be assigned a
99    /// [`glib::Error`][crate::glib::Error] from the `GTK_BUILDER_ERROR`, `G_MARKUP_ERROR` or
100    /// `G_VARIANT_PARSE_ERROR` domain.
101    ///
102    /// It’s not really reasonable to attempt to handle failures of this
103    /// call. The only reasonable thing to do when an error is detected is
104    /// to call `g_error()`.
105    /// ## `buffer`
106    /// the string to parse
107    /// ## `length`
108    /// the length of `buffer` (may be -1 if `buffer` is nul-terminated)
109    ///
110    /// # Returns
111    ///
112    /// A positive value on success, 0 if an error occurred
113    #[doc(alias = "gtk_builder_add_from_string")]
114    fn add_from_string(&self, buffer: &str) -> Result<(), glib::Error> {
115        let length = buffer.len();
116        unsafe {
117            let mut error = ptr::null_mut();
118            let exit_code = ffi::gtk_builder_add_from_string(
119                self.as_ref().to_glib_none().0,
120                buffer.to_glib_none().0,
121                length,
122                &mut error,
123            );
124            assert_eq!(exit_code == 0, !error.is_null());
125            if error.is_null() {
126                Ok(())
127            } else {
128                Err(from_glib_full(error))
129            }
130        }
131    }
132
133    /// Parses a resource file containing a [GtkBuilder UI definition][BUILDER-UI]
134    /// building only the requested objects and merges
135    /// them with the current contents of `self`.
136    ///
137    /// Upon errors 0 will be returned and `error` will be assigned a
138    /// [`glib::Error`][crate::glib::Error] from the `GTK_BUILDER_ERROR`, `G_MARKUP_ERROR` or `G_RESOURCE_ERROR`
139    /// domain.
140    ///
141    /// If you are adding an object that depends on an object that is not
142    /// its child (for instance a [`TreeView`][crate::TreeView] that depends on its
143    /// [`TreeModel`][crate::TreeModel]), you have to explicitly list all of them in `object_ids`.
144    /// ## `resource_path`
145    /// the path of the resource file to parse
146    /// ## `object_ids`
147    /// nul-terminated array of objects to build
148    ///
149    /// # Returns
150    ///
151    /// A positive value on success, 0 if an error occurred
152    #[doc(alias = "gtk_builder_add_objects_from_resource")]
153    fn add_objects_from_resource(
154        &self,
155        resource_path: &str,
156        object_ids: &[&str],
157    ) -> Result<(), glib::Error> {
158        unsafe {
159            let mut error = ptr::null_mut();
160            let exit_code = ffi::gtk_builder_add_objects_from_resource(
161                self.as_ref().to_glib_none().0,
162                resource_path.to_glib_none().0,
163                object_ids.to_glib_none().0,
164                &mut error,
165            );
166            assert_eq!(exit_code == 0, !error.is_null());
167            if error.is_null() {
168                Ok(())
169            } else {
170                Err(from_glib_full(error))
171            }
172        }
173    }
174    /// Parses a string containing a [GtkBuilder UI definition][BUILDER-UI]
175    /// building only the requested objects and merges
176    /// them with the current contents of `self`.
177    ///
178    /// Upon errors 0 will be returned and `error` will be assigned a
179    /// [`glib::Error`][crate::glib::Error] from the `GTK_BUILDER_ERROR` or `G_MARKUP_ERROR` domain.
180    ///
181    /// If you are adding an object that depends on an object that is not
182    /// its child (for instance a [`TreeView`][crate::TreeView] that depends on its
183    /// [`TreeModel`][crate::TreeModel]), you have to explicitly list all of them in `object_ids`.
184    /// ## `buffer`
185    /// the string to parse
186    /// ## `length`
187    /// the length of `buffer` (may be -1 if `buffer` is nul-terminated)
188    /// ## `object_ids`
189    /// nul-terminated array of objects to build
190    ///
191    /// # Returns
192    ///
193    /// A positive value on success, 0 if an error occurred
194    #[doc(alias = "gtk_builder_add_objects_from_string")]
195    fn add_objects_from_string(
196        &self,
197        buffer: &str,
198        object_ids: &[&str],
199    ) -> Result<(), glib::Error> {
200        let length = buffer.len();
201        unsafe {
202            let mut error = ptr::null_mut();
203            let exit_code = ffi::gtk_builder_add_objects_from_string(
204                self.as_ref().to_glib_none().0,
205                buffer.to_glib_none().0,
206                length,
207                object_ids.to_glib_none().0,
208                &mut error,
209            );
210            assert_eq!(exit_code == 0, !error.is_null());
211            if error.is_null() {
212                Ok(())
213            } else {
214                Err(from_glib_full(error))
215            }
216        }
217    }
218
219    #[doc(alias = "gtk_builder_connect_signals_full")]
220    fn connect_signals<
221        P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>,
222    >(
223        &self,
224        func: P,
225    ) {
226        let func_data: P = func;
227        unsafe extern "C" fn func_func<
228            P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>,
229        >(
230            builder: *mut ffi::GtkBuilder,
231            object: *mut glib::gobject_ffi::GObject,
232            signal_name: *const libc::c_char,
233            handler_name: *const libc::c_char,
234            connect_object: *mut glib::gobject_ffi::GObject,
235            flags: glib::gobject_ffi::GConnectFlags,
236            user_data: glib::ffi::gpointer,
237        ) {
238            assert!(connect_object.is_null(), "Connect object is not supported");
239            assert!(
240                flags & glib::gobject_ffi::G_CONNECT_SWAPPED == 0,
241                "Swapped signal handler is not supported"
242            );
243
244            let builder = from_glib_borrow(builder);
245            let object: Borrowed<glib::Object> = from_glib_borrow(object);
246            let signal_name: Borrowed<GString> = from_glib_borrow(signal_name);
247            let handler_name: Borrowed<GString> = from_glib_borrow(handler_name);
248            let callback: *mut P = user_data as *const _ as usize as *mut P;
249            let func = (*callback)(&builder, handler_name.as_str());
250            object.connect_unsafe(
251                signal_name.as_str(),
252                flags & glib::gobject_ffi::G_CONNECT_AFTER != 0,
253                move |args| func(args),
254            );
255        }
256        let func = Some(func_func::<P> as _);
257        let super_callback0: &P = &func_data;
258        unsafe {
259            ffi::gtk_builder_connect_signals_full(
260                self.as_ref().to_glib_none().0,
261                func,
262                super_callback0 as *const _ as usize as *mut _,
263            );
264        }
265    }
266
267    /// Main private entry point for building composite container
268    /// components from template XML.
269    ///
270    /// This is exported purely to let gtk-builder-tool validate
271    /// templates, applications have no need to call this function.
272    /// ## `widget`
273    /// the widget that is being extended
274    /// ## `template_type`
275    /// the type that the template is for
276    /// ## `buffer`
277    /// the string to parse
278    /// ## `length`
279    /// the length of `buffer` (may be -1 if `buffer` is nul-terminated)
280    ///
281    /// # Returns
282    ///
283    /// A positive value on success, 0 if an error occurred
284    #[doc(alias = "gtk_builder_extend_with_template")]
285    fn extend_with_template(
286        &self,
287        widget: &impl IsA<Widget>,
288        template_type: glib::types::Type,
289        buffer: &str,
290    ) -> Result<(), glib::Error> {
291        let length = buffer.len();
292        unsafe {
293            let mut error = ptr::null_mut();
294            let exit_code = ffi::gtk_builder_extend_with_template(
295                self.as_ref().to_glib_none().0,
296                widget.as_ref().to_glib_none().0,
297                template_type.into_glib(),
298                buffer.to_glib_none().0,
299                length,
300                &mut error,
301            );
302            assert_eq!(exit_code == 0, !error.is_null());
303            if error.is_null() {
304                Ok(())
305            } else {
306                Err(from_glib_full(error))
307            }
308        }
309    }
310}
311
312impl<O: IsA<Builder>> BuilderExtManual for O {}