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