From 32d36cbc47a9594d2e572e6b85761c4ba3ba4db8 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 17 Feb 2023 12:29:15 +0100 Subject: [PATCH 1/4] gio: Add AppLaunchContext subclassing support --- gio/src/subclass/app_launch_context.rs | 189 +++++++++++++++++++++++++ gio/src/subclass/mod.rs | 2 + 2 files changed, 191 insertions(+) create mode 100644 gio/src/subclass/app_launch_context.rs diff --git a/gio/src/subclass/app_launch_context.rs b/gio/src/subclass/app_launch_context.rs new file mode 100644 index 000000000000..acaf77979ff5 --- /dev/null +++ b/gio/src/subclass/app_launch_context.rs @@ -0,0 +1,189 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::ffi::c_char; + +use crate::{subclass::prelude::*, AppInfo, AppLaunchContext, File}; +use glib::{prelude::*, translate::*, GString, List, Variant}; + +pub trait AppLaunchContextImpl: ObjectImpl { + #[doc(alias = "get_display")] + fn display(&self, info: &AppInfo, files: List) -> Option { + self.parent_display(info, files) + } + #[doc(alias = "get_startup_notify_id")] + fn startup_notify_id(&self, info: &AppInfo, files: List) -> Option { + self.parent_startup_notify_id(info, files) + } + fn launch_failed(&self, startup_notify_id: &str) { + self.parent_launch_failed(startup_notify_id) + } + fn launch_started(&self, info: &AppInfo, platform_data: &Variant) { + self.parent_launch_started(info, platform_data) + } + fn launched(&self, info: &AppInfo, platform_data: &Variant) { + self.parent_launched(info, platform_data) + } +} + +pub trait AppLaunchContextImplExt: ObjectSubclass { + fn parent_display(&self, info: &AppInfo, files: List) -> Option; + fn parent_startup_notify_id(&self, info: &AppInfo, files: List) -> Option; + fn parent_launch_failed(&self, startup_notify_id: &str); + fn parent_launch_started(&self, info: &AppInfo, platform_data: &Variant); + fn parent_launched(&self, info: &AppInfo, platform_data: &Variant); +} + +impl AppLaunchContextImplExt for T { + fn parent_display(&self, info: &AppInfo, files: List) -> Option { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GAppLaunchContextClass; + (*parent_class).get_display.map(|f| { + from_glib_full(f( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + info.to_glib_none().0, + files.as_ptr() as *mut _, + )) + }) + } + } + + fn parent_startup_notify_id(&self, info: &AppInfo, files: List) -> Option { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GAppLaunchContextClass; + (*parent_class).get_startup_notify_id.map(|f| { + from_glib_full(f( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + info.to_glib_none().0, + files.as_ptr() as *mut _, + )) + }) + } + } + + fn parent_launch_failed(&self, startup_notify_id: &str) { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GAppLaunchContextClass; + if let Some(f) = (*parent_class).launch_failed { + f( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + startup_notify_id.to_glib_none().0, + ) + } + } + } + + fn parent_launch_started(&self, info: &AppInfo, platform_data: &Variant) { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GAppLaunchContextClass; + if let Some(f) = (*parent_class).launch_started { + f( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + info.to_glib_none().0, + platform_data.to_glib_none().0, + ) + } + } + } + + fn parent_launched(&self, info: &AppInfo, platform_data: &Variant) { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GAppLaunchContextClass; + if let Some(f) = (*parent_class).launched { + f( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + info.to_glib_none().0, + platform_data.to_glib_none().0, + ) + } + } + } +} + +unsafe impl IsSubclassable for AppLaunchContext { + fn class_init(class: &mut ::glib::Class) { + Self::parent_class_init::(class); + + let klass = class.as_mut(); + klass.get_display = Some(app_launch_context_get_display::); + klass.get_startup_notify_id = Some(app_launch_context_get_startup_notify_id::); + klass.launch_failed = Some(app_launch_context_launch_failed::); + klass.launched = Some(app_launch_context_launched::); + klass.launch_started = Some(app_launch_context_launch_started::); + } +} + +unsafe extern "C" fn app_launch_context_get_display( + ptr: *mut ffi::GAppLaunchContext, + infoptr: *mut ffi::GAppInfo, + filesptr: *mut glib::ffi::GList, +) -> *mut c_char { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.display(&from_glib_borrow(infoptr), List::from_glib_none(filesptr)) + .to_glib_full() +} + +unsafe extern "C" fn app_launch_context_get_startup_notify_id( + ptr: *mut ffi::GAppLaunchContext, + infoptr: *mut ffi::GAppInfo, + filesptr: *mut glib::ffi::GList, +) -> *mut c_char { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.startup_notify_id(&from_glib_borrow(infoptr), List::from_glib_none(filesptr)) + .to_glib_full() +} + +unsafe extern "C" fn app_launch_context_launch_failed( + ptr: *mut ffi::GAppLaunchContext, + startup_id: *const c_char, +) { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.launch_failed(&GString::from_glib_borrow(startup_id)) +} + +unsafe extern "C" fn app_launch_context_launched( + ptr: *mut ffi::GAppLaunchContext, + infoptr: *mut ffi::GAppInfo, + platform_ptr: *mut glib::ffi::GVariant, +) { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.launched(&from_glib_borrow(infoptr), &from_glib_borrow(platform_ptr)) +} + +unsafe extern "C" fn app_launch_context_launch_started( + ptr: *mut ffi::GAppLaunchContext, + infoptr: *mut ffi::GAppInfo, + platform_ptr: *mut glib::ffi::GVariant, +) { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.launch_started(&from_glib_borrow(infoptr), &from_glib_borrow(platform_ptr)) +} diff --git a/gio/src/subclass/mod.rs b/gio/src/subclass/mod.rs index de036e3f38f8..728c05bea3dc 100644 --- a/gio/src/subclass/mod.rs +++ b/gio/src/subclass/mod.rs @@ -2,6 +2,7 @@ mod action_group; mod action_map; +mod app_launch_context; mod application; mod async_initable; mod initable; @@ -20,6 +21,7 @@ pub mod prelude { pub use super::{ action_group::{ActionGroupImpl, ActionGroupImplExt}, action_map::{ActionMapImpl, ActionMapImplExt}, + app_launch_context::{AppLaunchContextImpl, AppLaunchContextImplExt}, application::{ApplicationImpl, ApplicationImplExt}, async_initable::{AsyncInitableImpl, AsyncInitableImplExt}, initable::{InitableImpl, InitableImplExt}, From 4da6553e1e1d8f9d23266528d5623d519fe3888e Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 17 Feb 2023 12:40:20 +0100 Subject: [PATCH 2/4] gio: Add FileMonitor subclassing support --- gio/src/subclass/file_monitor.rs | 85 ++++++++++++++++++++++++++++++++ gio/src/subclass/mod.rs | 2 + 2 files changed, 87 insertions(+) create mode 100644 gio/src/subclass/file_monitor.rs diff --git a/gio/src/subclass/file_monitor.rs b/gio/src/subclass/file_monitor.rs new file mode 100644 index 000000000000..95a5e9cf4305 --- /dev/null +++ b/gio/src/subclass/file_monitor.rs @@ -0,0 +1,85 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::{subclass::prelude::*, File, FileMonitor, FileMonitorEvent}; +use glib::{prelude::*, translate::*}; + +pub trait FileMonitorImpl: ObjectImpl { + fn changed(&self, file: &File, other_file: &File, event_type: FileMonitorEvent) { + self.parent_changed(file, other_file, event_type) + } + fn cancel(&self) -> bool { + self.parent_cancel() + } +} + +pub trait FileMonitorImplExt: ObjectSubclass { + fn parent_changed(&self, file: &File, other_file: &File, event_type: FileMonitorEvent); + fn parent_cancel(&self) -> bool; +} + +impl FileMonitorImplExt for T { + fn parent_changed(&self, file: &File, other_file: &File, event_type: FileMonitorEvent) { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GFileMonitorClass; + if let Some(f) = (*parent_class).changed { + f( + self.obj().unsafe_cast_ref::().to_glib_none().0, + file.to_glib_none().0, + other_file.to_glib_none().0, + event_type.into_glib(), + ) + } + } + } + + fn parent_cancel(&self) -> bool { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GFileMonitorClass; + let f = (*parent_class) + .cancel + .expect("No parent class implementation for \"cancel\""); + from_glib(f(self + .obj() + .unsafe_cast_ref::() + .to_glib_none() + .0)) + } + } +} + +unsafe impl IsSubclassable for FileMonitor { + fn class_init(class: &mut ::glib::Class) { + Self::parent_class_init::(class); + + let klass = class.as_mut(); + klass.changed = Some(file_monitor_changed::); + klass.cancel = Some(file_monitor_cancel::); + } +} + +unsafe extern "C" fn file_monitor_changed( + ptr: *mut ffi::GFileMonitor, + file: *mut ffi::GFile, + other_file: *mut ffi::GFile, + event: ffi::GFileMonitorEvent, +) { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.changed( + &from_glib_borrow(file), + &from_glib_borrow(other_file), + from_glib(event), + ) +} + +unsafe extern "C" fn file_monitor_cancel( + ptr: *mut ffi::GFileMonitor, +) -> glib::ffi::gboolean { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + + imp.cancel().into_glib() +} diff --git a/gio/src/subclass/mod.rs b/gio/src/subclass/mod.rs index 728c05bea3dc..7ac3fc33746d 100644 --- a/gio/src/subclass/mod.rs +++ b/gio/src/subclass/mod.rs @@ -5,6 +5,7 @@ mod action_map; mod app_launch_context; mod application; mod async_initable; +mod file_monitor; mod initable; mod input_stream; mod io_stream; @@ -24,6 +25,7 @@ pub mod prelude { app_launch_context::{AppLaunchContextImpl, AppLaunchContextImplExt}, application::{ApplicationImpl, ApplicationImplExt}, async_initable::{AsyncInitableImpl, AsyncInitableImplExt}, + file_monitor::{FileMonitorImpl, FileMonitorImplExt}, initable::{InitableImpl, InitableImplExt}, input_stream::{InputStreamImpl, InputStreamImplExt}, io_stream::{IOStreamImpl, IOStreamImplExt}, From a919867c82cfc2c34bb1d5c140ccbaa97dd47b80 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 17 Feb 2023 14:58:46 +0100 Subject: [PATCH 3/4] gio: Add Icon subclassing support --- gio/src/subclass/icon.rs | 174 +++++++++++++++++++++++++++++++++++++++ gio/src/subclass/mod.rs | 2 + 2 files changed, 176 insertions(+) create mode 100644 gio/src/subclass/icon.rs diff --git a/gio/src/subclass/icon.rs b/gio/src/subclass/icon.rs new file mode 100644 index 000000000000..8d4d38713dee --- /dev/null +++ b/gio/src/subclass/icon.rs @@ -0,0 +1,174 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, +}; + +use glib::{prelude::*, subclass::prelude::*, translate::*, Error}; + +use crate::Icon; + +pub trait IconImpl: ObjectImpl + Hash + PartialEq { + fn serialize(&self) -> Option { + self.parent_serialize() + } + + fn to_tokens(&self) -> Option<(Vec, i32)> { + self.parent_to_tokens() + } + + fn from_tokens(tokens: &[String], version: i32) -> Result { + Self::parent_from_tokens(tokens, version) + } +} + +pub trait IconImplExt: ObjectSubclass { + fn parent_serialize(&self) -> Option; + fn parent_to_tokens(&self) -> Option<(Vec, i32)>; + fn parent_from_tokens(tokens: &[String], version: i32) -> Result; +} + +impl IconImplExt for T { + fn parent_serialize(&self) -> Option { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().parent_interface::() as *const ffi::GIconIface; + + let func = (*parent_iface) + .serialize + .expect("No parent iface implementation for \"serialize\""); + from_glib_full(func(self.obj().unsafe_cast_ref::().to_glib_none().0)) + } + } + + fn parent_to_tokens(&self) -> Option<(Vec, i32)> { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().parent_interface::() as *const ffi::GIconIface; + + let tokens = std::ptr::null_mut(); + let mut version = std::mem::MaybeUninit::uninit(); + let func = (*parent_iface) + .to_tokens + .expect("No parent iface implementation for \"to_tokens\""); + let result = from_glib(func( + self.obj().unsafe_cast_ref::().to_glib_none().0, + tokens, + version.as_mut_ptr(), + )); + if result { + Some(( + FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(tokens), + version.assume_init(), + )) + } else { + None + } + } + } + + fn parent_from_tokens(tokens: &[String], version: i32) -> Result { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().parent_interface::() as *const ffi::GIconIface; + + let func = (*parent_iface) + .from_tokens + .expect("No parent iface implementation for \"from_tokens\""); + let mut err = std::ptr::null_mut(); + + let icon = func( + tokens.as_ptr() as *mut _, + tokens.len() as _, + version, + &mut err, + ); + if err.is_null() { + Ok(Icon::from_glib_full(icon)) + } else { + Err(from_glib_full(err)) + } + } + } +} + +unsafe impl IsImplementable for Icon { + fn interface_init(iface: &mut glib::Interface) { + let iface = iface.as_mut(); + + iface.to_tokens = Some(icon_to_tokens::); + iface.from_tokens = Some(icon_from_tokens::); + iface.serialize = Some(icon_serialize::); + iface.equal = Some(icon_equal::); + iface.hash = Some(icon_hash::); + } +} + +unsafe extern "C" fn icon_hash(icon: *mut ffi::GIcon) -> u32 { + let instance = &*(icon as *mut T::Instance); + let imp = instance.imp(); + let mut hasher = DefaultHasher::new(); + imp.hash(&mut hasher); + hasher.finish() as _ +} + +unsafe extern "C" fn icon_equal( + icon1: *mut ffi::GIcon, + icon2: *mut ffi::GIcon, +) -> glib::ffi::gboolean { + let instance = &*(icon1 as *mut T::Instance); + let imp1 = instance.imp(); + let instance = &*(icon2 as *mut T::Instance); + let imp2 = instance.imp(); + + imp1.eq(imp2).into_glib() +} + +unsafe extern "C" fn icon_serialize( + icon: *mut ffi::GIcon, +) -> *mut glib::ffi::GVariant { + let instance = &*(icon as *mut T::Instance); + let imp = instance.imp(); + + imp.serialize().to_glib_full() +} + +unsafe extern "C" fn icon_to_tokens( + icon: *mut ffi::GIcon, + tokens_ptr: *mut glib::ffi::GPtrArray, + version_ptr: *mut libc::c_int, +) -> glib::ffi::gboolean { + let instance = &*(icon as *mut T::Instance); + let imp = instance.imp(); + + if let Some((tokens, version)) = imp.to_tokens() { + *version_ptr = version; + *tokens_ptr = + *ToGlibContainerFromSlice::<*mut glib::ffi::GPtrArray>::to_glib_full_from_slice( + &tokens, + ); + true.into_glib() + } else { + false.into_glib() + } +} + +unsafe extern "C" fn icon_from_tokens( + tokens_ptr: *mut *mut libc::c_char, + n_tokens: i32, + version: i32, + err_ptr: *mut *mut glib::ffi::GError, +) -> *mut ffi::GIcon { + let tokens = String::from_glib_none_num_as_vec(tokens_ptr, n_tokens as _); + match T::from_tokens(tokens.as_slice(), version) { + Ok(icon) => icon.to_glib_full(), + Err(err) => { + *err_ptr = err.into_glib_ptr(); + std::ptr::null_mut() + } + } +} diff --git a/gio/src/subclass/mod.rs b/gio/src/subclass/mod.rs index 7ac3fc33746d..83485d10de62 100644 --- a/gio/src/subclass/mod.rs +++ b/gio/src/subclass/mod.rs @@ -6,6 +6,7 @@ mod app_launch_context; mod application; mod async_initable; mod file_monitor; +mod icon; mod initable; mod input_stream; mod io_stream; @@ -26,6 +27,7 @@ pub mod prelude { application::{ApplicationImpl, ApplicationImplExt}, async_initable::{AsyncInitableImpl, AsyncInitableImplExt}, file_monitor::{FileMonitorImpl, FileMonitorImplExt}, + icon::{IconImpl, IconImplExt}, initable::{InitableImpl, InitableImplExt}, input_stream::{InputStreamImpl, InputStreamImplExt}, io_stream::{IOStreamImpl, IOStreamImplExt}, From d191b45f1b7ea5b626d32a6d388055491db4acf6 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 17 Feb 2023 16:04:46 +0100 Subject: [PATCH 4/4] gio: Add LoadableIcon subclassing support --- gio/src/subclass/loadable_icon.rs | 263 ++++++++++++++++++++++++++++++ gio/src/subclass/mod.rs | 2 + 2 files changed, 265 insertions(+) create mode 100644 gio/src/subclass/loadable_icon.rs diff --git a/gio/src/subclass/loadable_icon.rs b/gio/src/subclass/loadable_icon.rs new file mode 100644 index 000000000000..3068c9229334 --- /dev/null +++ b/gio/src/subclass/loadable_icon.rs @@ -0,0 +1,263 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{future::Future, pin::Pin}; + +use crate::{ + subclass::prelude::*, AsyncResult, Cancellable, GioFuture, InputStream, LoadableIcon, LocalTask, +}; +use glib::{prelude::*, translate::*, GString}; + +pub trait LoadableIconImpl: IconImpl { + fn load( + &self, + size: i32, + cancellable: Option<&Cancellable>, + ) -> Result<(InputStream, Option), glib::Error> { + self.parent_load(size, cancellable) + } + + fn load_future( + &self, + size: i32, + ) -> Pin), glib::Error>> + 'static>> + { + self.parent_load_future(size) + } +} + +pub trait LoadableIconImplExt: ObjectSubclass { + fn parent_load( + &self, + size: i32, + cancellable: Option<&Cancellable>, + ) -> Result<(InputStream, Option), glib::Error>; + + fn parent_load_async(&self, size: i32, cancellable: Option<&Cancellable>, callback: C) + where + C: FnOnce(Result<(InputStream, Option), glib::Error>) + 'static; + + fn parent_load_future( + &self, + size: i32, + ) -> Pin), glib::Error>> + 'static>>; +} + +impl LoadableIconImplExt for T { + fn parent_load( + &self, + size: i32, + cancellable: Option<&Cancellable>, + ) -> Result<(InputStream, Option), glib::Error> { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().parent_interface::() + as *const ffi::GLoadableIconIface; + + let func = (*parent_iface) + .load + .expect("No parent iface implementation for \"load\""); + let mut err = std::ptr::null_mut(); + let mut string = std::ptr::null_mut(); + let stream = func( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + size, + &mut string, + cancellable.to_glib_none().0, + &mut err, + ); + if err.is_null() { + Ok((from_glib_full(stream), from_glib_full(string))) + } else { + Err(from_glib_full(err)) + } + } + } + + fn parent_load_async(&self, size: i32, cancellable: Option<&Cancellable>, callback: C) + where + C: FnOnce(Result<(InputStream, Option), glib::Error>) + 'static, + { + unsafe { + let main_context = glib::MainContext::ref_thread_default(); + let is_main_context_owner = main_context.is_owner(); + let has_acquired_main_context = (!is_main_context_owner) + .then(|| main_context.acquire().ok()) + .flatten(); + assert!( + is_main_context_owner || has_acquired_main_context.is_some(), + "Async operations only allowed if the thread is owning the MainContext" + ); + + let type_data = T::type_data(); + let parent_iface = type_data.as_ref().parent_interface::() + as *const ffi::GLoadableIconIface; + let f = (*parent_iface) + .load_async + .expect("no parent \"load_async\" implementation"); + let finish = (*parent_iface) + .load_finish + .expect("no parent \"load_finish\" implementation"); + + let user_data: Box<(glib::thread_guard::ThreadGuard, _)> = + Box::new((glib::thread_guard::ThreadGuard::new(callback), finish)); + + unsafe extern "C" fn parent_load_async_trampoline( + source_object_ptr: *mut glib::gobject_ffi::GObject, + res: *mut ffi::GAsyncResult, + user_data: glib::ffi::gpointer, + ) where + R: FnOnce(Result<(InputStream, Option), glib::Error>) + 'static, + { + let mut error = std::ptr::null_mut(); + let cb: Box<( + glib::thread_guard::ThreadGuard, + fn( + *mut ffi::GLoadableIcon, + *mut ffi::GAsyncResult, + *mut *mut libc::c_char, + *mut *mut glib::ffi::GError, + ) -> *mut ffi::GInputStream, + )> = Box::from_raw(user_data as *mut _); + let mut typeptr = std::ptr::null_mut(); + let stream = cb.1(source_object_ptr as _, res, &mut typeptr, &mut error); + let result = if error.is_null() { + Ok((from_glib_full(stream), from_glib_full(typeptr))) + } else { + Err(from_glib_full(error)) + }; + let cb = cb.0.into_inner(); + cb(result); + } + + let callback = parent_load_async_trampoline::; + f( + self.obj() + .unsafe_cast_ref::() + .to_glib_none() + .0, + size, + cancellable.to_glib_none().0, + Some(callback), + Box::into_raw(user_data) as *mut _, + ); + } + } + + fn parent_load_future( + &self, + size: i32, + ) -> Pin), glib::Error>> + 'static>> + { + Box::pin(GioFuture::new( + &self.ref_counted(), + move |imp, cancellable, send| { + imp.parent_load_async(size, Some(cancellable), move |res| { + send.resolve(res); + }); + }, + )) + } +} + +unsafe impl IsImplementable for LoadableIcon { + fn interface_init(iface: &mut glib::Interface) { + let iface = iface.as_mut(); + + iface.load = Some(icon_load::); + iface.load_async = Some(icon_load_async::); + iface.load_finish = Some(icon_load_finish::); + } +} + +unsafe extern "C" fn icon_load( + icon: *mut ffi::GLoadableIcon, + size: i32, + typeptr: *mut *mut libc::c_char, + cancellableptr: *mut ffi::GCancellable, + errorptr: *mut *mut glib::ffi::GError, +) -> *mut ffi::GInputStream { + let instance = &*(icon as *mut T::Instance); + let imp = instance.imp(); + + let cancellable: Borrowed> = from_glib_borrow(cancellableptr); + + let ret = imp.load(size, cancellable.as_ref().as_ref()); + match ret { + Ok((stream, icon_type)) => { + if !typeptr.is_null() { + *typeptr = icon_type.to_glib_none().0; + } + + stream.to_glib_full() + } + Err(err) => { + *errorptr = err.into_glib_ptr(); + *typeptr = std::ptr::null_mut(); + + std::ptr::null_mut() + } + } +} + +#[derive(Clone, glib::Boxed)] +#[boxed_type(name = "GLoadableIconReturnType")] +// Needed for having the required Value traits by GTask API +struct LoadableIconReturnType(InputStream, Option); + +unsafe extern "C" fn icon_load_async( + icon: *mut ffi::GLoadableIcon, + size: i32, + cancellableptr: *mut ffi::GCancellable, + callbackptr: ffi::GAsyncReadyCallback, + dataptr: glib::ffi::gpointer, +) { + let instance = &*(icon as *mut T::Instance); + let imp = instance.imp(); + let wrap: LoadableIcon = from_glib_none(icon); + let cancellable: Option = from_glib_none(cancellableptr); + + let closure = move |task: LocalTask, + source_object: Option<&glib::Object>| { + let result: *mut ffi::GAsyncResult = task.upcast_ref::().to_glib_none().0; + let source_object: *mut glib::gobject_ffi::GObject = source_object.to_glib_none().0; + callbackptr.unwrap()(source_object, result, dataptr) + }; + + let t = LocalTask::new( + Some(wrap.upcast_ref::()), + cancellable.as_ref(), + closure, + ); + + glib::MainContext::default().spawn_local(async move { + let res = imp.load_future(size).await; + t.return_result(res.map(|(s, t)| LoadableIconReturnType(s, t))); + }); +} + +unsafe extern "C" fn icon_load_finish( + _icon: *mut ffi::GLoadableIcon, + resultptr: *mut ffi::GAsyncResult, + typeptr: *mut *mut libc::c_char, + errorptr: *mut *mut glib::ffi::GError, +) -> *mut ffi::GInputStream { + let res: AsyncResult = from_glib_none(resultptr); + let t = res.downcast::>().unwrap(); + let ret = t.propagate(); + match ret { + Ok(rt) => { + let (stream, icon_type) = (rt.0, rt.1); + if !typeptr.is_null() { + *typeptr = icon_type.to_glib_full(); + } + stream.to_glib_full() + } + Err(err) => { + *errorptr = err.into_glib_ptr(); + std::ptr::null_mut() + } + } +} diff --git a/gio/src/subclass/mod.rs b/gio/src/subclass/mod.rs index 83485d10de62..559ad34762f1 100644 --- a/gio/src/subclass/mod.rs +++ b/gio/src/subclass/mod.rs @@ -11,6 +11,7 @@ mod initable; mod input_stream; mod io_stream; mod list_model; +mod loadable_icon; mod output_stream; mod seekable; @@ -32,6 +33,7 @@ pub mod prelude { input_stream::{InputStreamImpl, InputStreamImplExt}, io_stream::{IOStreamImpl, IOStreamImplExt}, list_model::{ListModelImpl, ListModelImplExt}, + loadable_icon::{LoadableIconImpl, LoadableIconImplExt}, output_stream::{OutputStreamImpl, OutputStreamImplExt}, seekable::{SeekableImpl, SeekableImplExt}, };