1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::Builder;
4 use glib::prelude::*;
5 use glib::translate::*;
6 use glib::GString;
7 use glib::Object;
8 use std::path::Path;
9 
10 impl Builder {
11     #[doc(alias = "gtk_builder_new_from_file")]
from_file<T: AsRef<Path>>(file_path: T) -> Builder12     pub fn from_file<T: AsRef<Path>>(file_path: T) -> Builder {
13         assert_initialized_main_thread!();
14         unsafe {
15             from_glib_full(ffi::gtk_builder_new_from_file(
16                 file_path.as_ref().to_glib_none().0,
17             ))
18         }
19     }
20 }
21 
22 pub trait BuilderExtManual: 'static {
23     #[doc(alias = "gtk_builder_get_object")]
24     #[doc(alias = "get_object")]
object<T: IsA<Object>>(&self, name: &str) -> Option<T>25     fn object<T: IsA<Object>>(&self, name: &str) -> Option<T>;
26 
27     #[doc(alias = "gtk_builder_add_from_file")]
add_from_file<T: AsRef<Path>>(&self, file_path: T) -> Result<(), glib::Error>28     fn add_from_file<T: AsRef<Path>>(&self, file_path: T) -> Result<(), glib::Error>;
29     #[doc(alias = "gtk_builder_connect_signals_full")]
connect_signals< P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>, >( &self, func: P, )30     fn connect_signals<
31         P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>,
32     >(
33         &self,
34         func: P,
35     );
36 }
37 
38 impl<O: IsA<Builder>> BuilderExtManual for O {
object<T: IsA<Object>>(&self, name: &str) -> Option<T>39     fn object<T: IsA<Object>>(&self, name: &str) -> Option<T> {
40         unsafe {
41             Option::<Object>::from_glib_none(ffi::gtk_builder_get_object(
42                 self.upcast_ref().to_glib_none().0,
43                 name.to_glib_none().0,
44             ))
45             .and_then(|obj| obj.dynamic_cast::<T>().ok())
46         }
47     }
48 
add_from_file<T: AsRef<Path>>(&self, file_path: T) -> Result<(), glib::Error>49     fn add_from_file<T: AsRef<Path>>(&self, file_path: T) -> Result<(), glib::Error> {
50         unsafe {
51             let mut error = ::std::ptr::null_mut();
52             ffi::gtk_builder_add_from_file(
53                 self.upcast_ref().to_glib_none().0,
54                 file_path.as_ref().to_glib_none().0,
55                 &mut error,
56             );
57             if error.is_null() {
58                 Ok(())
59             } else {
60                 Err(from_glib_full(error))
61             }
62         }
63     }
64 
connect_signals< P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>, >( &self, func: P, )65     fn connect_signals<
66         P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>,
67     >(
68         &self,
69         func: P,
70     ) {
71         let func_data: P = func;
72         unsafe extern "C" fn func_func<
73             P: FnMut(&Builder, &str) -> Box<dyn Fn(&[glib::Value]) -> Option<glib::Value> + 'static>,
74         >(
75             builder: *mut ffi::GtkBuilder,
76             object: *mut glib::gobject_ffi::GObject,
77             signal_name: *const libc::c_char,
78             handler_name: *const libc::c_char,
79             connect_object: *mut glib::gobject_ffi::GObject,
80             flags: glib::gobject_ffi::GConnectFlags,
81             user_data: glib::ffi::gpointer,
82         ) {
83             assert!(connect_object.is_null(), "Connect object is not supported");
84             assert!(
85                 flags & glib::gobject_ffi::G_CONNECT_SWAPPED == 0,
86                 "Swapped signal handler is not supported"
87             );
88 
89             let builder = from_glib_borrow(builder);
90             let object: Borrowed<glib::Object> = from_glib_borrow(object);
91             let signal_name: Borrowed<GString> = from_glib_borrow(signal_name);
92             let handler_name: Borrowed<GString> = from_glib_borrow(handler_name);
93             let callback: *mut P = user_data as *const _ as usize as *mut P;
94             let func = (*callback)(&builder, handler_name.as_str());
95             object
96                 .connect_unsafe(
97                     signal_name.as_str(),
98                     flags & glib::gobject_ffi::G_CONNECT_AFTER != 0,
99                     move |args| func(args),
100                 )
101                 .expect("Failed to connect to builder signal");
102         }
103         let func = Some(func_func::<P> as _);
104         let super_callback0: &P = &func_data;
105         unsafe {
106             ffi::gtk_builder_connect_signals_full(
107                 self.as_ref().to_glib_none().0,
108                 func,
109                 super_callback0 as *const _ as usize as *mut _,
110             );
111         }
112     }
113 }
114