gtk4/auto/
uri_launcher.rs1use crate::{ffi, Window};
6use glib::{
7 prelude::*,
8 signal::{connect_raw, SignalHandlerId},
9 translate::*,
10};
11use std::{boxed::Box as Box_, pin::Pin};
12
13glib::wrapper! {
14 #[doc(alias = "GtkUriLauncher")]
15 pub struct UriLauncher(Object<ffi::GtkUriLauncher, ffi::GtkUriLauncherClass>);
16
17 match fn {
18 type_ => || ffi::gtk_uri_launcher_get_type(),
19 }
20}
21
22impl UriLauncher {
23 #[doc(alias = "gtk_uri_launcher_new")]
24 pub fn new(uri: &str) -> UriLauncher {
25 assert_initialized_main_thread!();
26 unsafe { from_glib_full(ffi::gtk_uri_launcher_new(uri.to_glib_none().0)) }
27 }
28
29 pub fn builder() -> UriLauncherBuilder {
34 UriLauncherBuilder::new()
35 }
36
37 #[doc(alias = "gtk_uri_launcher_get_uri")]
38 #[doc(alias = "get_uri")]
39 pub fn uri(&self) -> Option<glib::GString> {
40 unsafe { from_glib_none(ffi::gtk_uri_launcher_get_uri(self.to_glib_none().0)) }
41 }
42
43 #[doc(alias = "gtk_uri_launcher_launch")]
44 pub fn launch<P: FnOnce(Result<(), glib::Error>) + 'static>(
45 &self,
46 parent: Option<&impl IsA<Window>>,
47 cancellable: Option<&impl IsA<gio::Cancellable>>,
48 callback: P,
49 ) {
50 let main_context = glib::MainContext::ref_thread_default();
51 let is_main_context_owner = main_context.is_owner();
52 let has_acquired_main_context = (!is_main_context_owner)
53 .then(|| main_context.acquire().ok())
54 .flatten();
55 assert!(
56 is_main_context_owner || has_acquired_main_context.is_some(),
57 "Async operations only allowed if the thread is owning the MainContext"
58 );
59
60 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
61 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
62 unsafe extern "C" fn launch_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
63 _source_object: *mut glib::gobject_ffi::GObject,
64 res: *mut gio::ffi::GAsyncResult,
65 user_data: glib::ffi::gpointer,
66 ) {
67 let mut error = std::ptr::null_mut();
68 let _ = ffi::gtk_uri_launcher_launch_finish(_source_object as *mut _, res, &mut error);
69 let result = if error.is_null() {
70 Ok(())
71 } else {
72 Err(from_glib_full(error))
73 };
74 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
75 Box_::from_raw(user_data as *mut _);
76 let callback: P = callback.into_inner();
77 callback(result);
78 }
79 let callback = launch_trampoline::<P>;
80 unsafe {
81 ffi::gtk_uri_launcher_launch(
82 self.to_glib_none().0,
83 parent.map(|p| p.as_ref()).to_glib_none().0,
84 cancellable.map(|p| p.as_ref()).to_glib_none().0,
85 Some(callback),
86 Box_::into_raw(user_data) as *mut _,
87 );
88 }
89 }
90
91 pub fn launch_future(
92 &self,
93 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
94 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
95 let parent = parent.map(ToOwned::to_owned);
96 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
97 obj.launch(
98 parent.as_ref().map(::std::borrow::Borrow::borrow),
99 Some(cancellable),
100 move |res| {
101 send.resolve(res);
102 },
103 );
104 }))
105 }
106
107 #[doc(alias = "gtk_uri_launcher_set_uri")]
108 #[doc(alias = "uri")]
109 pub fn set_uri(&self, uri: Option<&str>) {
110 unsafe {
111 ffi::gtk_uri_launcher_set_uri(self.to_glib_none().0, uri.to_glib_none().0);
112 }
113 }
114
115 #[cfg(feature = "v4_10")]
116 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
117 #[doc(alias = "uri")]
118 pub fn connect_uri_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
119 unsafe extern "C" fn notify_uri_trampoline<F: Fn(&UriLauncher) + 'static>(
120 this: *mut ffi::GtkUriLauncher,
121 _param_spec: glib::ffi::gpointer,
122 f: glib::ffi::gpointer,
123 ) {
124 let f: &F = &*(f as *const F);
125 f(&from_glib_borrow(this))
126 }
127 unsafe {
128 let f: Box_<F> = Box_::new(f);
129 connect_raw(
130 self.as_ptr() as *mut _,
131 b"notify::uri\0".as_ptr() as *const _,
132 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
133 notify_uri_trampoline::<F> as *const (),
134 )),
135 Box_::into_raw(f),
136 )
137 }
138 }
139}
140
141#[cfg(feature = "v4_10")]
142#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
143impl Default for UriLauncher {
144 fn default() -> Self {
145 glib::object::Object::new::<Self>()
146 }
147}
148
149#[must_use = "The builder must be built to be used"]
154pub struct UriLauncherBuilder {
155 builder: glib::object::ObjectBuilder<'static, UriLauncher>,
156}
157
158impl UriLauncherBuilder {
159 fn new() -> Self {
160 Self {
161 builder: glib::object::Object::builder(),
162 }
163 }
164
165 #[cfg(feature = "v4_10")]
166 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
167 pub fn uri(self, uri: impl Into<glib::GString>) -> Self {
168 Self {
169 builder: self.builder.property("uri", uri.into()),
170 }
171 }
172
173 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
176 pub fn build(self) -> UriLauncher {
177 assert_initialized_main_thread!();
178 self.builder.build()
179 }
180}