use crate::{
prelude::*, CompletionCell, CompletionContext, CompletionProposal, CompletionProvider,
};
use glib::subclass::prelude::*;
use glib::translate::*;
use std::{future::Future, pin::Pin};
pub trait CompletionProviderImpl: ObjectImpl {
fn activate(&self, context: &CompletionContext, proposal: &CompletionProposal) {
self.parent_activate(context, proposal)
}
fn display(
&self,
context: &CompletionContext,
proposal: &CompletionProposal,
cell: &CompletionCell,
) {
self.parent_display(context, proposal, cell)
}
fn title(&self) -> Option<glib::GString> {
self.parent_title()
}
fn priority(&self, context: &CompletionContext) -> i32 {
self.parent_priority(context)
}
fn is_trigger(&self, iter: >k::TextIter, c: char) -> bool {
self.parent_is_trigger(iter, c)
}
fn key_activates(
&self,
context: &CompletionContext,
proposal: &CompletionProposal,
keyval: gdk::Key,
state: gdk::ModifierType,
) -> bool {
self.parent_key_activates(context, proposal, keyval, state)
}
fn refilter(&self, context: &CompletionContext, model: &gio::ListModel) {
self.parent_refilter(context, model)
}
fn list_alternates(
&self,
context: &CompletionContext,
proposal: &CompletionProposal,
) -> Vec<CompletionProposal> {
self.parent_list_alternates(context, proposal)
}
fn populate(&self, context: &CompletionContext) -> Result<gio::ListModel, glib::Error> {
self.parnet_populate(context)
}
fn populate_future(
&self,
context: &CompletionContext,
) -> Pin<Box<dyn Future<Output = Result<gio::ListModel, glib::Error>>>> {
self.parent_populate_future(context)
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::CompletionProviderImplExt> Sealed for T {}
}
pub trait CompletionProviderImplExt: sealed::Sealed + ObjectSubclass {
fn parent_activate(&self, context: &CompletionContext, proposal: &CompletionProposal) {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.activate
.expect("no parent \"activate\" implementation");
func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
proposal.to_glib_none().0,
)
}
}
fn parent_title(&self) -> Option<glib::GString> {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.get_title
.expect("no parent \"get_title\" implementation");
from_glib_full(func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
))
}
}
fn parent_display(
&self,
context: &CompletionContext,
proposal: &CompletionProposal,
cell: &CompletionCell,
) {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.display
.expect("no parent \"display\" implementation");
func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
proposal.to_glib_none().0,
cell.to_glib_none().0,
)
}
}
fn parent_priority(&self, context: &CompletionContext) -> i32 {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.get_priority
.expect("no parent \"get_priority\" implementation");
func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
)
}
}
fn parent_is_trigger(&self, iter: >k::TextIter, c: char) -> bool {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.is_trigger
.expect("no parent \"is_trigger\" implementation");
from_glib(func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
iter.to_glib_none().0,
c.into_glib(),
))
}
}
fn parent_list_alternates(
&self,
context: &CompletionContext,
proposal: &CompletionProposal,
) -> Vec<CompletionProposal> {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.list_alternates
.expect("no parent \"list_alternates\" implementation");
let output = func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
proposal.to_glib_none().0,
);
FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(output)
}
}
fn parent_refilter(&self, context: &CompletionContext, model: &gio::ListModel) {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.refilter
.expect("no parent \"refilter\" implementation");
func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
model.to_glib_none().0,
)
}
}
fn parent_key_activates(
&self,
context: &CompletionContext,
proposal: &CompletionProposal,
keyval: gdk::Key,
state: gdk::ModifierType,
) -> bool {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.key_activates
.expect("no parent \"key_activates\" implementation");
from_glib(func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
proposal.to_glib_none().0,
keyval.into_glib(),
state.into_glib(),
))
}
}
fn parnet_populate(&self, context: &CompletionContext) -> Result<gio::ListModel, glib::Error> {
unsafe {
let type_data = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let func = (*parent_iface)
.populate
.expect("no parent \"populate\" implementation");
let mut error = std::ptr::null_mut();
let result = func(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
&mut error,
);
if error.is_null() {
Ok(from_glib_full(result))
} else {
Err(from_glib_full(error))
}
}
}
fn parent_populate_future(
&self,
context: &CompletionContext,
) -> Pin<Box<dyn Future<Output = Result<gio::ListModel, glib::Error>>>> {
let context = context.clone();
Box::pin(gio::GioFuture::new(
&self.ref_counted(),
move |imp, cancellable, send| {
imp.parent_pouplate_async(&context, Some(cancellable), move |res| {
send.resolve(res);
});
},
))
}
#[allow(clippy::type_complexity)]
fn parent_pouplate_async<
Q: IsA<gio::Cancellable>,
C: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
>(
&self,
context: &CompletionContext,
cancellable: Option<&Q>,
callback: C,
) {
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 = Self::type_data();
let parent_iface = type_data.as_ref().parent_interface::<CompletionProvider>()
as *const ffi::GtkSourceCompletionProviderInterface;
let f = (*parent_iface)
.populate_async
.expect("no parent \"populate_async\" implementation");
let finish = (*parent_iface)
.populate_finish
.expect("no parent \"populate_finish\" implementation");
let user_data: Box<(glib::thread_guard::ThreadGuard<C>, _)> =
Box::new((glib::thread_guard::ThreadGuard::new(callback), finish));
unsafe extern "C" fn parent_populate_async_trampoline<
C: FnOnce(Result<gio::ListModel, 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<C>,
fn(
*mut ffi::GtkSourceCompletionProvider,
*mut gio::ffi::GAsyncResult,
*mut *mut glib::ffi::GError,
) -> *mut gio::ffi::GListModel,
)> = Box::from_raw(user_data as *mut _);
let model = cb.1(source_object_ptr as _, res, &mut error);
let result = if error.is_null() {
Ok(from_glib_full(model))
} 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_populate_async_trampoline::<C>;
f(
self.obj()
.unsafe_cast_ref::<CompletionProvider>()
.to_glib_none()
.0,
context.to_glib_none().0,
cancellable.to_glib_none().0,
Some(callback),
Box::into_raw(user_data) as *mut _,
);
}
}
}
impl<T: CompletionProviderImpl> CompletionProviderImplExt for T {}
unsafe impl<T: CompletionProviderImpl> IsImplementable<T> for CompletionProvider {
fn interface_init(iface: &mut glib::Interface<Self>) {
let iface = iface.as_mut();
iface.activate = Some(completion_provider_activate::<T>);
iface.display = Some(completion_provider_display::<T>);
iface.get_title = Some(completion_provider_get_title::<T>);
iface.get_priority = Some(completion_provider_get_priority::<T>);
iface.is_trigger = Some(completion_provider_is_trigger::<T>);
iface.refilter = Some(completion_provider_refilter::<T>);
iface.key_activates = Some(completion_provider_key_activates::<T>);
iface.list_alternates = Some(completion_provider_list_alternates::<T>);
iface.populate = Some(completion_provider_populate::<T>);
iface.populate_async = Some(completion_provider_populate_async::<T>);
iface.populate_finish = Some(completion_provider_populate_finish::<T>);
}
}
unsafe extern "C" fn completion_provider_activate<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
proposal: *mut ffi::GtkSourceCompletionProposal,
) {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.activate(&from_glib_borrow(context), &from_glib_borrow(proposal))
}
unsafe extern "C" fn completion_provider_display<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
proposal: *mut ffi::GtkSourceCompletionProposal,
cell: *mut ffi::GtkSourceCompletionCell,
) {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.display(
&from_glib_borrow(context),
&from_glib_borrow(proposal),
&from_glib_borrow(cell),
)
}
unsafe extern "C" fn completion_provider_get_title<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
) -> *mut libc::c_char {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.title().to_glib_full()
}
unsafe extern "C" fn completion_provider_get_priority<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
) -> i32 {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.priority(&from_glib_borrow(context))
}
unsafe extern "C" fn completion_provider_is_trigger<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
iter: *const gtk::ffi::GtkTextIter,
c: u32,
) -> glib::ffi::gboolean {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.is_trigger(
&from_glib_borrow(iter),
TryFrom::try_from(c).expect("Invalid character"),
)
.into_glib()
}
unsafe extern "C" fn completion_provider_refilter<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
model: *mut gio::ffi::GListModel,
) {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.refilter(&from_glib_borrow(context), &from_glib_borrow(model))
}
unsafe extern "C" fn completion_provider_key_activates<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
proposal: *mut ffi::GtkSourceCompletionProposal,
keyval: u32,
state: gdk::ffi::GdkModifierType,
) -> glib::ffi::gboolean {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.key_activates(
&from_glib_borrow(context),
&from_glib_borrow(proposal),
from_glib(keyval),
from_glib(state),
)
.into_glib()
}
unsafe extern "C" fn completion_provider_list_alternates<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
proposal: *mut ffi::GtkSourceCompletionProposal,
) -> *mut glib::ffi::GPtrArray {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
imp.list_alternates(&from_glib_borrow(context), &from_glib_borrow(proposal))
.to_glib_full()
}
unsafe extern "C" fn completion_provider_populate<T: CompletionProviderImpl>(
provider: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
error: *mut *mut glib::ffi::GError,
) -> *mut gio::ffi::GListModel {
let instance = &*(provider as *mut T::Instance);
let imp = instance.imp();
let res = imp.populate(&from_glib_borrow(context));
match res {
Ok(model) => {
*error = std::ptr::null_mut();
model.to_glib_full()
}
Err(err) => {
*error = err.into_glib_ptr();
std::ptr::null_mut()
}
}
}
unsafe extern "C" fn completion_provider_populate_async<T: CompletionProviderImpl>(
ptr: *mut ffi::GtkSourceCompletionProvider,
context: *mut ffi::GtkSourceCompletionContext,
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 context: CompletionContext = from_glib_none(context);
let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable_ptr);
let closure = move |result: gio::LocalTask<gio::ListModel>,
source_object: Option<&CompletionProvider>| {
let result: *mut gio::ffi::GAsyncResult = result
.unsafe_cast_ref::<gio::AsyncResult>()
.to_glib_none()
.0;
let source_object = source_object
.map(|p| p.unsafe_cast_ref::<glib::Object>())
.to_glib_none()
.0;
callback.unwrap()(source_object, result, user_data)
};
let t = gio::LocalTask::new(None, cancellable.as_ref(), closure);
glib::MainContext::default().spawn_local(async move {
let res = imp.populate_future(&context).await;
t.return_result(res);
});
}
unsafe extern "C" fn completion_provider_populate_finish<T: CompletionProviderImpl>(
_ptr: *mut ffi::GtkSourceCompletionProvider,
res_ptr: *mut gio::ffi::GAsyncResult,
error_ptr: *mut *mut glib::ffi::GError,
) -> *mut gio::ffi::GListModel {
let res: gio::AsyncResult = from_glib_none(res_ptr);
let t = res.downcast::<gio::LocalTask<gio::ListModel>>().unwrap();
let ret = t.propagate();
match ret {
Ok(model) => model.to_glib_full(),
Err(e) => {
*error_ptr = e.into_glib_ptr();
std::ptr::null_mut()
}
}
}