use std::{future::Future, pin::Pin};
use glib::{translate::*, Value};
use crate::{ffi, prelude::*, subclass::prelude::*, Clipboard, ContentFormats, ContentProvider};
pub trait ContentProviderImpl: ObjectImpl + ObjectSubclass<Type: IsA<ContentProvider>> {
fn content_changed(&self) {
self.parent_content_changed()
}
fn attach_clipboard(&self, clipboard: &Clipboard) {
self.parent_attach_clipboard(clipboard)
}
fn detach_clipboard(&self, clipboard: &Clipboard) {
self.parent_detach_clipboard(clipboard)
}
fn formats(&self) -> ContentFormats {
self.parent_formats()
}
fn storable_formats(&self) -> ContentFormats {
self.parent_storable_formats()
}
fn write_mime_type_future(
&self,
mime_type: &str,
stream: &gio::OutputStream,
io_priority: glib::Priority,
) -> Pin<Box<dyn Future<Output = Result<(), glib::Error>> + 'static>> {
self.parent_write_mime_type_future(mime_type, stream, io_priority)
}
fn value(&self, type_: glib::Type) -> Result<Value, glib::Error> {
self.parent_value(type_)
}
}
pub trait ContentProviderImplExt: ContentProviderImpl {
fn parent_content_changed(&self) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
if let Some(f) = (*parent_class).content_changed {
f(self
.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0)
}
}
}
fn parent_attach_clipboard(&self, clipboard: &Clipboard) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
if let Some(f) = (*parent_class).attach_clipboard {
f(
self.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0,
clipboard.to_glib_none().0,
)
}
}
}
fn parent_detach_clipboard(&self, clipboard: &Clipboard) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
if let Some(f) = (*parent_class).detach_clipboard {
f(
self.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0,
clipboard.to_glib_none().0,
)
}
}
}
fn parent_formats(&self) -> ContentFormats {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
let f = (*parent_class)
.ref_formats
.expect("no parent \"ref_formats\" implementation");
let ret = f(self
.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0);
from_glib_full(ret)
}
}
fn parent_storable_formats(&self) -> ContentFormats {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
let f = (*parent_class)
.ref_storable_formats
.expect("no parent \"ref_storable_formats\" implementation");
let ret = f(self
.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0);
from_glib_full(ret)
}
}
#[allow(clippy::type_complexity)]
fn parent_write_mime_type_async<
Q: IsA<gio::Cancellable>,
R: FnOnce(Result<(), glib::Error>) + 'static,
>(
&self,
mime_type: &str,
stream: &gio::OutputStream,
io_priority: glib::Priority,
cancellable: Option<&Q>,
callback: R,
) {
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 data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
let f = (*parent_class)
.write_mime_type_async
.expect("no parent \"write_mime_type_async\" implementation");
let finish = (*parent_class)
.write_mime_type_finish
.expect("no parent \"write_mime_type_finish\" implementation");
let user_data: Box<(glib::thread_guard::ThreadGuard<R>, _)> =
Box::new((glib::thread_guard::ThreadGuard::new(callback), finish));
unsafe extern "C" fn parent_write_mime_type_async_trampoline<
R: FnOnce(Result<(), glib::Error>) + 'static,
>(
source_object_ptr: *mut glib::gobject_ffi::GObject,
res: *mut gio::ffi::GAsyncResult,
user_data: glib::ffi::gpointer,
) {
let mut error = std::ptr::null_mut();
let cb: Box<(
glib::thread_guard::ThreadGuard<R>,
fn(
*mut ffi::GdkContentProvider,
*mut gio::ffi::GAsyncResult,
*mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean,
)> = Box::from_raw(user_data as *mut _);
cb.1(source_object_ptr as _, res, &mut error);
let result = if error.is_null() {
Ok(())
} else {
Err(from_glib_full(error))
};
let cb = cb.0.into_inner();
cb(result);
}
let cancellable = cancellable.map(|p| p.as_ref());
let callback = parent_write_mime_type_async_trampoline::<R>;
f(
self.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0,
mime_type.to_glib_none().0,
stream.to_glib_none().0,
io_priority.into_glib(),
cancellable.to_glib_none().0,
Some(callback),
Box::into_raw(user_data) as *mut _,
);
}
}
fn parent_write_mime_type_future(
&self,
mime_type: &str,
stream: &gio::OutputStream,
io_priority: glib::Priority,
) -> Pin<Box<dyn Future<Output = Result<(), glib::Error>> + 'static>> {
let stream = stream.clone();
let mime_type = String::from(mime_type);
Box::pin(gio::GioFuture::new(
&self.ref_counted(),
move |imp, cancellable, send| {
imp.parent_write_mime_type_async(
&mime_type,
&stream,
io_priority,
Some(cancellable),
move |res| {
send.resolve(res);
},
);
},
))
}
fn parent_value(&self, type_: glib::Type) -> Result<Value, glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkContentProviderClass;
let f = (*parent_class)
.get_value
.expect("no parent \"get_value\" implementation");
let mut value = Value::from_type(type_);
let mut error = std::ptr::null_mut();
f(
self.obj()
.unsafe_cast_ref::<ContentProvider>()
.to_glib_none()
.0,
value.to_glib_none_mut().0,
&mut error,
);
if error.is_null() {
Ok(value)
} else {
Err(from_glib_full(error))
}
}
}
}
impl<T: ContentProviderImpl> ContentProviderImplExt for T {}
unsafe impl<T: ContentProviderImpl> IsSubclassable<T> for ContentProvider {
fn class_init(class: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(class);
let klass = class.as_mut();
klass.content_changed = Some(content_provider_content_changed::<T>);
klass.attach_clipboard = Some(content_provider_attach_clipboard::<T>);
klass.detach_clipboard = Some(content_provider_detach_clipboard::<T>);
klass.ref_formats = Some(content_provider_formats::<T>);
klass.ref_storable_formats = Some(content_provider_storable_formats::<T>);
klass.write_mime_type_async = Some(content_provider_write_mime_type_async::<T>);
klass.write_mime_type_finish = Some(content_provider_write_mime_type_finish);
klass.get_value = Some(content_provider_get_value::<T>);
}
}
unsafe extern "C" fn content_provider_content_changed<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.content_changed()
}
unsafe extern "C" fn content_provider_attach_clipboard<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
clipboard_ptr: *mut ffi::GdkClipboard,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let clipboard = from_glib_borrow(clipboard_ptr);
imp.attach_clipboard(&clipboard)
}
unsafe extern "C" fn content_provider_detach_clipboard<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
clipboard_ptr: *mut ffi::GdkClipboard,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let clipboard = from_glib_borrow(clipboard_ptr);
imp.detach_clipboard(&clipboard)
}
unsafe extern "C" fn content_provider_formats<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
) -> *mut ffi::GdkContentFormats {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.formats().into_glib_ptr()
}
unsafe extern "C" fn content_provider_storable_formats<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
) -> *mut ffi::GdkContentFormats {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.storable_formats().into_glib_ptr()
}
unsafe extern "C" fn content_provider_write_mime_type_async<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
mime_type_ptr: *const libc::c_char,
stream_ptr: *mut gio::ffi::GOutputStream,
priority: libc::c_int,
cancellable_ptr: *mut gio::ffi::GCancellable,
callback: gio::ffi::GAsyncReadyCallback,
user_data: glib::ffi::gpointer,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let wrap: ContentProvider = from_glib_none(ptr);
let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable_ptr);
let mime_type: glib::GString = from_glib_none(mime_type_ptr);
let stream: gio::OutputStream = from_glib_none(stream_ptr);
let closure = move |task: gio::LocalTask<bool>, source_object: Option<&glib::Object>| {
let result: *mut gio::ffi::GAsyncResult =
task.upcast_ref::<gio::AsyncResult>().to_glib_none().0;
let source_object: *mut glib::gobject_ffi::GObject = source_object.to_glib_none().0;
callback.unwrap()(source_object, result, user_data)
};
let t = gio::LocalTask::new(
Some(wrap.upcast_ref::<glib::Object>()),
cancellable.as_ref(),
closure,
);
glib::MainContext::default().spawn_local(async move {
let res = imp
.write_mime_type_future(
mime_type.as_str(),
stream.unsafe_cast_ref::<gio::OutputStream>(),
from_glib(priority),
)
.await;
t.return_result(res.map(|_t| true));
});
}
unsafe extern "C" fn content_provider_write_mime_type_finish(
_ptr: *mut ffi::GdkContentProvider,
res_ptr: *mut gio::ffi::GAsyncResult,
error_ptr: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let res: gio::AsyncResult = from_glib_none(res_ptr);
let t = res.downcast::<gio::LocalTask<bool>>().unwrap();
let ret = t.propagate();
match ret {
Ok(v) => {
debug_assert!(v);
true.into_glib()
}
Err(e) => {
if !error_ptr.is_null() {
*error_ptr = e.into_glib_ptr();
}
false.into_glib()
}
}
}
unsafe extern "C" fn content_provider_get_value<T: ContentProviderImpl>(
ptr: *mut ffi::GdkContentProvider,
value_ptr: *mut glib::gobject_ffi::GValue,
error_ptr: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let value: Value = from_glib_none(value_ptr);
let ret = imp.value(value.type_());
match ret {
Ok(v) => {
glib::gobject_ffi::g_value_copy(v.to_glib_none().0, value_ptr);
true.into_glib()
}
Err(e) => {
if !error_ptr.is_null() {
*error_ptr = e.into_glib_ptr();
}
false.into_glib()
}
}
}