From ff2f0492b56f2ffa9841cef506519a96b787facc Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 17 Feb 2023 14:58:46 +0100 Subject: [PATCH] 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},