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 {}