1use std::boxed::Box as Box_;
7use std::pin::Pin;
8
9use glib::prelude::*;
10use glib::signal::{SignalHandlerId, connect_raw};
11use glib::translate::*;
12
13use crate::{Image, MemoryFormatSelection, SandboxSelector, ffi};
14
15glib::wrapper! {
16 #[doc(alias = "GlyLoader")]
17 pub struct Loader(Object<ffi::GlyLoader, ffi::GlyLoaderClass>);
18
19 match fn {
20 type_ => || ffi::gly_loader_get_type(),
21 }
22}
23
24impl Loader {
25 #[doc(alias = "gly_loader_new")]
26 pub fn new(file: &impl IsA<gio::File>) -> Loader {
27 assert_initialized_main_thread!();
28 unsafe { from_glib_full(ffi::gly_loader_new(file.as_ref().to_glib_none().0)) }
29 }
30
31 #[doc(alias = "gly_loader_new_for_bytes")]
32 #[doc(alias = "new_for_bytes")]
33 pub fn for_bytes(bytes: &glib::Bytes) -> Loader {
34 assert_initialized_main_thread!();
35 unsafe { from_glib_full(ffi::gly_loader_new_for_bytes(bytes.to_glib_none().0)) }
36 }
37
38 #[doc(alias = "gly_loader_new_for_stream")]
39 #[doc(alias = "new_for_stream")]
40 pub fn for_stream(stream: &impl IsA<gio::InputStream>) -> Loader {
41 assert_initialized_main_thread!();
42 unsafe {
43 from_glib_full(ffi::gly_loader_new_for_stream(
44 stream.as_ref().to_glib_none().0,
45 ))
46 }
47 }
48
49 pub fn builder() -> LoaderBuilder {
57 LoaderBuilder::new()
58 }
59
60 #[doc(alias = "gly_loader_load")]
61 pub fn load(&self) -> Result<Image, glib::Error> {
62 unsafe {
63 let mut error = std::ptr::null_mut();
64 let ret = ffi::gly_loader_load(self.to_glib_none().0, &mut error);
65 if error.is_null() {
66 Ok(from_glib_full(ret))
67 } else {
68 Err(from_glib_full(error))
69 }
70 }
71 }
72
73 #[doc(alias = "gly_loader_load_async")]
74 pub fn load_async<P: FnOnce(Result<Image, glib::Error>) + 'static>(
75 &self,
76 cancellable: Option<&impl IsA<gio::Cancellable>>,
77 callback: P,
78 ) {
79 let main_context = glib::MainContext::ref_thread_default();
80 let is_main_context_owner = main_context.is_owner();
81 let has_acquired_main_context = (!is_main_context_owner)
82 .then(|| main_context.acquire().ok())
83 .flatten();
84 assert!(
85 is_main_context_owner || has_acquired_main_context.is_some(),
86 "Async operations only allowed if the thread is owning the MainContext"
87 );
88
89 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
90 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
91 unsafe extern "C" fn load_async_trampoline<
92 P: FnOnce(Result<Image, glib::Error>) + 'static,
93 >(
94 _source_object: *mut glib::gobject_ffi::GObject,
95 res: *mut gio::ffi::GAsyncResult,
96 user_data: glib::ffi::gpointer,
97 ) {
98 unsafe {
99 let mut error = std::ptr::null_mut();
100 let ret = ffi::gly_loader_load_finish(_source_object as *mut _, res, &mut error);
101 let result = if error.is_null() {
102 Ok(from_glib_full(ret))
103 } else {
104 Err(from_glib_full(error))
105 };
106 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
107 Box_::from_raw(user_data as *mut _);
108 let callback: P = callback.into_inner();
109 callback(result);
110 }
111 }
112 let callback = load_async_trampoline::<P>;
113 unsafe {
114 ffi::gly_loader_load_async(
115 self.to_glib_none().0,
116 cancellable.map(|p| p.as_ref()).to_glib_none().0,
117 Some(callback),
118 Box_::into_raw(user_data) as *mut _,
119 );
120 }
121 }
122
123 pub fn load_future(
124 &self,
125 ) -> Pin<Box_<dyn std::future::Future<Output = Result<Image, glib::Error>> + 'static>> {
126 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
127 obj.load_async(Some(cancellable), move |res| {
128 send.resolve(res);
129 });
130 }))
131 }
132
133 #[doc(alias = "gly_loader_set_accepted_memory_formats")]
134 pub fn set_accepted_memory_formats(&self, memory_format_selection: MemoryFormatSelection) {
135 unsafe {
136 ffi::gly_loader_set_accepted_memory_formats(
137 self.to_glib_none().0,
138 memory_format_selection.into_glib(),
139 );
140 }
141 }
142
143 #[doc(alias = "gly_loader_set_apply_transformations")]
144 pub fn set_apply_transformations(&self, apply_transformations: bool) {
145 unsafe {
146 ffi::gly_loader_set_apply_transformations(
147 self.to_glib_none().0,
148 apply_transformations.into_glib(),
149 );
150 }
151 }
152
153 #[doc(alias = "gly_loader_set_sandbox_selector")]
154 #[doc(alias = "sandbox-selector")]
155 pub fn set_sandbox_selector(&self, sandbox_selector: SandboxSelector) {
156 unsafe {
157 ffi::gly_loader_set_sandbox_selector(
158 self.to_glib_none().0,
159 sandbox_selector.into_glib(),
160 );
161 }
162 }
163
164 #[doc(alias = "apply-transformation")]
165 pub fn is_apply_transformation(&self) -> bool {
166 ObjectExt::property(self, "apply-transformation")
167 }
168
169 #[doc(alias = "apply-transformation")]
170 pub fn set_apply_transformation(&self, apply_transformation: bool) {
171 ObjectExt::set_property(self, "apply-transformation", apply_transformation)
172 }
173
174 pub fn bytes(&self) -> Option<glib::Bytes> {
175 ObjectExt::property(self, "bytes")
176 }
177
178 pub fn cancellable(&self) -> Option<gio::Cancellable> {
179 ObjectExt::property(self, "cancellable")
180 }
181
182 pub fn set_cancellable<P: IsA<gio::Cancellable>>(&self, cancellable: Option<&P>) {
183 ObjectExt::set_property(self, "cancellable", cancellable)
184 }
185
186 pub fn file(&self) -> Option<gio::File> {
187 ObjectExt::property(self, "file")
188 }
189
190 #[doc(alias = "memory-format-selection")]
191 pub fn memory_format_selection(&self) -> MemoryFormatSelection {
192 ObjectExt::property(self, "memory-format-selection")
193 }
194
195 #[doc(alias = "memory-format-selection")]
196 pub fn set_memory_format_selection(&self, memory_format_selection: MemoryFormatSelection) {
197 ObjectExt::set_property(self, "memory-format-selection", memory_format_selection)
198 }
199
200 #[doc(alias = "sandbox-selector")]
201 pub fn sandbox_selector(&self) -> SandboxSelector {
202 ObjectExt::property(self, "sandbox-selector")
203 }
204
205 pub fn stream(&self) -> Option<gio::InputStream> {
206 ObjectExt::property(self, "stream")
207 }
208
209 #[doc(alias = "gly_loader_get_mime_types")]
210 #[doc(alias = "get_mime_types")]
211 pub fn mime_types() -> Vec<glib::GString> {
212 assert_initialized_main_thread!();
213 unsafe { FromGlibPtrContainer::from_glib_full(ffi::gly_loader_get_mime_types()) }
214 }
215
216 #[doc(alias = "gly_loader_get_mime_types_async")]
217 #[doc(alias = "get_mime_types_async")]
218 pub fn mime_types_async<P: FnOnce(Result<Vec<glib::GString>, glib::Error>) + 'static>(
219 cancellable: Option<&impl IsA<gio::Cancellable>>,
220 callback: P,
221 ) {
222 assert_initialized_main_thread!();
223
224 let main_context = glib::MainContext::ref_thread_default();
225 let is_main_context_owner = main_context.is_owner();
226 let has_acquired_main_context = (!is_main_context_owner)
227 .then(|| main_context.acquire().ok())
228 .flatten();
229 assert!(
230 is_main_context_owner || has_acquired_main_context.is_some(),
231 "Async operations only allowed if the thread is owning the MainContext"
232 );
233
234 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
235 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
236 unsafe extern "C" fn mime_types_async_trampoline<
237 P: FnOnce(Result<Vec<glib::GString>, glib::Error>) + 'static,
238 >(
239 _source_object: *mut glib::gobject_ffi::GObject,
240 res: *mut gio::ffi::GAsyncResult,
241 user_data: glib::ffi::gpointer,
242 ) {
243 unsafe {
244 let mut error = std::ptr::null_mut();
245 let ret = ffi::gly_loader_get_mime_types_finish(res, &mut error);
246 let result = if error.is_null() {
247 Ok(FromGlibPtrContainer::from_glib_full(ret))
248 } else {
249 Err(from_glib_full(error))
250 };
251 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
252 Box_::from_raw(user_data as *mut _);
253 let callback: P = callback.into_inner();
254 callback(result);
255 }
256 }
257 let callback = mime_types_async_trampoline::<P>;
258 unsafe {
259 ffi::gly_loader_get_mime_types_async(
260 cancellable.map(|p| p.as_ref()).to_glib_none().0,
261 Some(callback),
262 Box_::into_raw(user_data) as *mut _,
263 );
264 }
265 }
266
267 pub fn mime_types_future() -> Pin<
268 Box_<dyn std::future::Future<Output = Result<Vec<glib::GString>, glib::Error>> + 'static>,
269 > {
270 skip_assert_initialized!();
271 Box_::pin(gio::GioFuture::new(&(), move |_obj, cancellable, send| {
272 Self::mime_types_async(Some(cancellable), move |res| {
273 send.resolve(res);
274 });
275 }))
276 }
277
278 #[doc(alias = "apply-transformation")]
279 pub fn connect_apply_transformation_notify<F: Fn(&Self) + Send + Sync + 'static>(
280 &self,
281 f: F,
282 ) -> SignalHandlerId {
283 unsafe extern "C" fn notify_apply_transformation_trampoline<
284 F: Fn(&Loader) + Send + Sync + 'static,
285 >(
286 this: *mut ffi::GlyLoader,
287 _param_spec: glib::ffi::gpointer,
288 f: glib::ffi::gpointer,
289 ) {
290 unsafe {
291 let f: &F = &*(f as *const F);
292 f(&from_glib_borrow(this))
293 }
294 }
295 unsafe {
296 let f: Box_<F> = Box_::new(f);
297 connect_raw(
298 self.as_ptr() as *mut _,
299 c"notify::apply-transformation".as_ptr() as *const _,
300 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
301 notify_apply_transformation_trampoline::<F> as *const (),
302 )),
303 Box_::into_raw(f),
304 )
305 }
306 }
307
308 #[doc(alias = "cancellable")]
309 pub fn connect_cancellable_notify<F: Fn(&Self) + Send + Sync + 'static>(
310 &self,
311 f: F,
312 ) -> SignalHandlerId {
313 unsafe extern "C" fn notify_cancellable_trampoline<
314 F: Fn(&Loader) + Send + Sync + 'static,
315 >(
316 this: *mut ffi::GlyLoader,
317 _param_spec: glib::ffi::gpointer,
318 f: glib::ffi::gpointer,
319 ) {
320 unsafe {
321 let f: &F = &*(f as *const F);
322 f(&from_glib_borrow(this))
323 }
324 }
325 unsafe {
326 let f: Box_<F> = Box_::new(f);
327 connect_raw(
328 self.as_ptr() as *mut _,
329 c"notify::cancellable".as_ptr() as *const _,
330 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
331 notify_cancellable_trampoline::<F> as *const (),
332 )),
333 Box_::into_raw(f),
334 )
335 }
336 }
337
338 #[doc(alias = "memory-format-selection")]
339 pub fn connect_memory_format_selection_notify<F: Fn(&Self) + Send + Sync + 'static>(
340 &self,
341 f: F,
342 ) -> SignalHandlerId {
343 unsafe extern "C" fn notify_memory_format_selection_trampoline<
344 F: Fn(&Loader) + Send + Sync + 'static,
345 >(
346 this: *mut ffi::GlyLoader,
347 _param_spec: glib::ffi::gpointer,
348 f: glib::ffi::gpointer,
349 ) {
350 unsafe {
351 let f: &F = &*(f as *const F);
352 f(&from_glib_borrow(this))
353 }
354 }
355 unsafe {
356 let f: Box_<F> = Box_::new(f);
357 connect_raw(
358 self.as_ptr() as *mut _,
359 c"notify::memory-format-selection".as_ptr() as *const _,
360 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
361 notify_memory_format_selection_trampoline::<F> as *const (),
362 )),
363 Box_::into_raw(f),
364 )
365 }
366 }
367
368 #[doc(alias = "sandbox-selector")]
369 pub fn connect_sandbox_selector_notify<F: Fn(&Self) + Send + Sync + 'static>(
370 &self,
371 f: F,
372 ) -> SignalHandlerId {
373 unsafe extern "C" fn notify_sandbox_selector_trampoline<
374 F: Fn(&Loader) + Send + Sync + 'static,
375 >(
376 this: *mut ffi::GlyLoader,
377 _param_spec: glib::ffi::gpointer,
378 f: glib::ffi::gpointer,
379 ) {
380 unsafe {
381 let f: &F = &*(f as *const F);
382 f(&from_glib_borrow(this))
383 }
384 }
385 unsafe {
386 let f: Box_<F> = Box_::new(f);
387 connect_raw(
388 self.as_ptr() as *mut _,
389 c"notify::sandbox-selector".as_ptr() as *const _,
390 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
391 notify_sandbox_selector_trampoline::<F> as *const (),
392 )),
393 Box_::into_raw(f),
394 )
395 }
396 }
397}
398
399impl Default for Loader {
400 fn default() -> Self {
401 glib::object::Object::new::<Self>()
402 }
403}
404
405#[must_use = "The builder must be built to be used"]
410pub struct LoaderBuilder {
411 builder: glib::object::ObjectBuilder<'static, Loader>,
412}
413
414impl LoaderBuilder {
415 fn new() -> Self {
416 Self {
417 builder: glib::object::Object::builder(),
418 }
419 }
420
421 pub fn apply_transformation(self, apply_transformation: bool) -> Self {
422 Self {
423 builder: self
424 .builder
425 .property("apply-transformation", apply_transformation),
426 }
427 }
428
429 pub fn bytes(self, bytes: &glib::Bytes) -> Self {
430 Self {
431 builder: self.builder.property("bytes", bytes.clone()),
432 }
433 }
434
435 pub fn cancellable(self, cancellable: &impl IsA<gio::Cancellable>) -> Self {
436 Self {
437 builder: self
438 .builder
439 .property("cancellable", cancellable.clone().upcast()),
440 }
441 }
442
443 pub fn file(self, file: &impl IsA<gio::File>) -> Self {
444 Self {
445 builder: self.builder.property("file", file.clone().upcast()),
446 }
447 }
448
449 pub fn memory_format_selection(self, memory_format_selection: MemoryFormatSelection) -> Self {
450 Self {
451 builder: self
452 .builder
453 .property("memory-format-selection", memory_format_selection),
454 }
455 }
456
457 pub fn sandbox_selector(self, sandbox_selector: SandboxSelector) -> Self {
458 Self {
459 builder: self.builder.property("sandbox-selector", sandbox_selector),
460 }
461 }
462
463 pub fn stream(self, stream: &impl IsA<gio::InputStream>) -> Self {
464 Self {
465 builder: self.builder.property("stream", stream.clone().upcast()),
466 }
467 }
468
469 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
472 pub fn build(self) -> Loader {
473 assert_initialized_main_thread!();
474 self.builder.build()
475 }
476}
477
478unsafe impl Send for Loader {}
479unsafe impl Sync for Loader {}