-
-
Notifications
You must be signed in to change notification settings - Fork 8
No current support for custom auto-complete #131
Comments
@GuillaumeGomez Since you won't be doing this, can I get your opinion on what I said about using a Rust trait instead of normal interface implementations before I attempt to PR this? Also, would such a PR be welcome? |
If the API is easy to use in the end for the users, then I'm fine with it. We currently generate most of the API with gir, which allows us to have a low maintenance. With all this in mind, this library doesn't change much (even less since the version 4 has been released) so I guess it's ok to have more manual code. So if you have the motivation to do it, then please do so. It's very welcome. |
I'm going to attempt it.... I'm not sure how well it will turn out, but I'm attempting it.
@sdroege Could I get these links? The most basic example that is currently here would be best, so that I just see what's important. |
So, Now this is an interface. So you would have to add something like https://github.com/gtk-rs/gio/blob/master/src/subclass/seekable.rs . Instead of the virtual methods of At that point you would then have enough bindings to actually implement some |
Below that with |
I've been trying to make heads or tails out of GObject enough to be able to write something like this, and I'm not getting anywhere. Is there some documentation that exists that will clearly spell out how this is supposed to work? Even if it doesn't have the complete story, I know nothing right now aside from how to use the existing bindings. I'm seeing a jumble of macros, traits, structs, etc. when I look at the existing source, with no clear pattern to them. When I think that I've figured something out, I invariably find something else a few hours later that contradicts it. I don't think that I can do this without at least some documentation — I have literally no idea how GObject works, yet I'm trying to implement bindings in another language! It's mildly absurd, and I'll need some help if it is going to happen. |
Maybe https://developer.gnome.org/gobject/2.62/pt02.html can help? That's the C part of the whole story. From looking at the pieces of the I agree that we need to put something into a more complete documentation here to explain how all the pieces fit together but I don't really have the time to do that right now, it's going to be a day or two of work. So feel free to ask questions for now. |
I think that probably the best way to help clarify this is if I put some questions here as I come across them — that should allow me to get an authoritative answer in a reasonable amount of time (as opposed to hours of digging through source to infer something that's probably wrong, which is what I've been doing). The first issue that I'm having relates to "an Impl trait with the virtual methods." I created a trait that looks like this: use glib::subclass::prelude::*;
pub trait CompletionImpl: ObjectImpl + Send + 'static {
//...
} and, I presume, that the methods from here should be mirrored into this trait, but it's not clear what the signatures should be. For example, take the C method fn get_name(&self) -> glib::char::Char; //Why would this type exist if it isn't used at the low level like this? The same pointer stuff below applies here to create 2 additional possibilities.
fn get_name(&self) -> char; //The seekable example seems to use native Rust types/
fn get_name(&self) -> *char; //Maybe Rust's unsafe pointers should be used?
fn get_name(&self) -> *mut char; //The pointer is mutable in C, maybe it is here too? Of course, only one of them is likely correct, but I have no basis from which to make that determination (for this function, or for others). What are the rules for rewriting these signatures? I know that it seems like I haven't gotten very far — that's because what I've done so far as mostly consisted of reading things and trying to make heads or tails out of what's going on. My learning style usually requires me to first use some well-written documentation to get a good conceptual foundation, and only then go on to writing code (or doing whatever it is that I'm trying to learn). For obvious reasons though, that didn't work very well in this case, so I'm now trying something different. |
You would use the corresponding proper Rust types. So for example Now the function doesn't return a
No worries about that :) This is not exactly easy stuff. Personally I would tackle this by reading other code in the bindings that does similar things and try to understand that, probably having problems understanding how things fit together and then ask based on the existing code. But let's just go through it one by one here if you prefer that. |
I forgot to actually write the whole signature in the end, sorry. That would be |
Okay... what you've said has been very helpful. Thank you :) I think that I have a correct Impl trait. Is there any way to have the compiler check it? I'd rather have that happen at each step, to avoid the situation where there's some issue somewhere, and things mysteriously don't work (This usually happens when I work with C APIs, after implementing a big chunk of stuff without the ability to test each step. OpenGl has been the worst offender.). Here's what I have: use crate::CompletionActivation;
use crate::CompletionContext;
use crate::CompletionInfo;
use crate::CompletionProposal;
use crate::CompletionProvider;
use glib::subclass::prelude::*;
pub trait CompletionImpl: ObjectImpl + Send + 'static {
fn get_name(&self, obj: &CompletionProvider) -> glib::GString;
fn get_icon(&self, obj: &CompletionProvider) -> Option<gdk_pixbuf::Pixbuf>;
fn get_icon_name(&self, obj: &CompletionProvider) -> Option<glib::GString>;
fn get_gicon(&self, obg: &CompletionProvider) -> Option<gio_sys::GIcon>;
fn populate(&self, obg: &CompletionProvider, context: &CompletionContext);
fn get_activation(&self, obg: &CompletionProvider) -> CompletionActivation;
fn provider_match(&self, obg: &CompletionProvider, context: &CompletionContext) -> bool;
fn get_info_widget(
&self,
obg: &CompletionProvider,
proposal: &CompletionProposal,
) -> Option<gtk::Widget>;
fn update_info(
&self,
obg: &CompletionProvider,
proposal: &CompletionProposal,
info: &CompletionInfo,
);
fn get_start_iter(
&self,
obg: &CompletionProvider,
context: &CompletionContext,
proposal: &CompletionProposal,
iter: >k::TextIter,
) -> bool;
fn activate_proposal(
&self,
obg: &CompletionProvider,
proposal: &CompletionProposal,
iter: >k::TextIter,
) -> bool;
fn get_interactive_delay(&self, obj: &CompletionProvider) -> i32;
fn get_priority(&self, obg: &CompletionProvider) -> i32;
} |
Not really. If it compiles then there's no mistake the compiler could catch. The trait looks generally good to me, not obvious problems. When implementing the other pieces you might notice that things don't fit together in a way the compiler likes it (or the implementation doesn't make sense). But that would be exactly the next step. You'd add one by one the |
When moving on to implementing the glue functions (the functions that the C code can call, which then delegate to the Rust implementation, such as this one — I'm not sure what the standard name is for these, so I must clearly define the terms that I'm using.), once again, I'm having trouble with determining the method signature. Specifically, I am working on the unsafe fn get_name_glue<T: ObjectSubclass + CompletionImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *glib_sys::gchar; , but, it would appear that no such type exists in |
It's unsafe fn get_name_glue<T: ObjectSubclass>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *mut c_char; Also for consistency your trait should be called |
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/blob/master/gstreamer/src/subclass/uri_handler.rs#L75 would be an example of an interface that has functions returning strings. |
So, in order to get it to build Here's what I have, after changing the signature. unsafe impl<T: ObjectSubclass + CompletionProviderImpl> IsImplementable<T> for CompletionProvider {
unsafe extern "C" fn interface_init(iface: glib::glib_sys::gpointer, _iface_data: glib::glib_sys::gpointer) {
let iface = &mut *(iface as *mut gtk_source_sys::GtkSourceCompletionProviderIface);
iface.get_name = Some(completion_provider_get_name::<T>);
}
}
unsafe extern "C" fn completion_provider_get_name<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *const libc::c_char{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_name(&from_glib_borrow(completion_provider)).to_glib_full()
} |
That seems like a weird inconsistency between the C struct definition in the docs and in the sourceview -sys crate.
This is correct, yes, see below
It does, it has a
Looks good to me :) |
I'm having some trouble with the unsafe extern "C" fn completion_provider_get_icon<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *mut gdk_pixbuf_sys::GdkPixbuf{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
match imp.get_icon(&from_glib_borrow(completion_provider)) {
Some(pixbuf) => pixbuf.to_glib(), //method not found
None => std::ptr::null_mut()
}
imp.get_icon(&from_glib_borrow(completion_provider)).to_glib() //method not found here either, in the real code I only want one of something like this, but I'm showing both here to demonstrate both things that I know to try
} |
This should be |
It seems like What hacks are needed to make this work? I tried to find some examples in the code base, but I can't find anything that looks like an interface as I'm trying to do, just calls like this one, where the function is being used to call into GTK's C code, not to allow GTK's C code to call into Rust. There also don't seem to be any hacks going on in the examples that I can find. For now, I'm trying it without anything special (just calling the function and accessing .0) to allow me to continue working, but since you said that there should be hacks there, it definitely seems like the right thing to make sure that I'm doing it properly. Also, thank you so much for all your help! I feel like I'm finally getting somewhere with understanding this system :). Sorry if I'm asking too many questions, I'll try to reduce it a bit. |
With the assumption that use crate::CompletionActivation;
use crate::CompletionContext;
use crate::CompletionInfo;
use crate::CompletionProposal;
use crate::CompletionProvider;
use glib::translate::*;
use glib::subclass::prelude::*;
pub trait CompletionProviderImpl: ObjectImpl + Send + 'static {
fn get_name(&self, obj: &CompletionProvider) -> glib::GString;
fn get_icon(&self, obj: &CompletionProvider) -> Option<gdk_pixbuf::Pixbuf>;
fn get_icon_name(&self, obj: &CompletionProvider) -> Option<glib::GString>;
fn get_gicon(&self, obg: &CompletionProvider) -> Option<gio::Icon>;
fn populate(&self, obg: &CompletionProvider, context: &CompletionContext);
fn get_activation(&self, obg: &CompletionProvider) -> CompletionActivation;
fn provide_match(&self, obg: &CompletionProvider, context: &CompletionContext) -> bool;
fn get_info_widget(
&self,
obg: &CompletionProvider,
proposal: &CompletionProposal,
) -> Option<gtk::Widget>;
fn update_info(
&self,
obg: &CompletionProvider,
proposal: &CompletionProposal,
info: &CompletionInfo,
);
fn get_start_iter(
&self,
obg: &CompletionProvider,
context: &CompletionContext,
proposal: &CompletionProposal,
iter: >k::TextIter,
) -> bool;
fn activate_proposal(
&self,
obg: &CompletionProvider,
proposal: &CompletionProposal,
iter: >k::TextIter,
) -> bool;
fn get_interactive_delay(&self, obj: &CompletionProvider) -> i32;
fn get_priority(&self, obg: &CompletionProvider) -> i32;
}
unsafe impl<T: ObjectSubclass + CompletionProviderImpl> IsImplementable<T> for CompletionProvider {
unsafe extern "C" fn interface_init(iface: glib::glib_sys::gpointer, _iface_data: glib::glib_sys::gpointer) {
let iface = &mut *(iface as *mut gtk_source_sys::GtkSourceCompletionProviderIface);
iface.get_name = Some(completion_provider_get_name::<T>);
iface.get_icon = Some(completion_provider_get_icon::<T>);
iface.get_icon_name = Some(completion_provider_get_icon_name::<T>);
iface.get_gicon = Some(completion_provider_get_gicon::<T>);
iface.populate = Some(completion_provider_populate::<T>);
iface.get_activation = Some(completion_provider_get_activation::<T>);
iface.match_ = Some(completion_provider_provide_match::<T>);
iface.get_info_widget = Some(completion_provider_get_info_widget::<T>);
iface.update_info = Some(completion_provider_update_info::<T>);
iface.get_start_iter = Some(completion_provider_get_start_iter::<T>);
iface.activate_proposal = Some(completion_provider_activate_proposal::<T>);
iface.get_interactive_delay = Some(completion_provider_get_interactive_delay::<T>);
iface.get_priority = Some(completion_provider_get_priority::<T>);
}
}
unsafe extern "C" fn completion_provider_get_name<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *const libc::c_char{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_name(&from_glib_borrow(completion_provider)).to_glib_full()
}
unsafe extern "C" fn completion_provider_get_icon<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *mut gdk_pixbuf_sys::GdkPixbuf{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_icon(&from_glib_borrow(completion_provider)).to_glib_none().0 //method not found here either, in the real code I only want one of something like this, but I'm showing both here to demonstrate both things that I know to try
}
unsafe extern "C" fn completion_provider_get_icon_name<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *const libc::c_char{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_icon_name(&from_glib_borrow(completion_provider)).to_glib_none().0
}
unsafe extern "C" fn completion_provider_get_gicon<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> *mut gio_sys::GIcon{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_gicon(&from_glib_borrow(completion_provider)).to_glib_none().0
}
unsafe extern "C" fn completion_provider_populate<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider, context: *mut gtk_source_sys::GtkSourceCompletionContext){
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.populate(&from_glib_borrow(completion_provider), &from_glib_borrow(context))
}
unsafe extern "C" fn completion_provider_get_activation<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> gtk_source_sys::GtkSourceCompletionActivation{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_activation(&from_glib_borrow(completion_provider)).to_glib()
}
unsafe extern "C" fn completion_provider_provide_match<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider, context: *mut gtk_source_sys::GtkSourceCompletionContext) -> glib_sys::gboolean{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.provide_match(&from_glib_borrow(completion_provider), &from_glib_borrow(context)).to_glib()
}
unsafe extern "C" fn completion_provider_get_info_widget<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider, proposal: *mut gtk_source_sys::GtkSourceCompletionProposal) -> *mut gtk_sys::GtkWidget{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_info_widget(&from_glib_borrow(completion_provider), &from_glib_borrow(proposal)).to_glib_none().0
}
unsafe extern "C" fn completion_provider_update_info<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider, proposal: *mut gtk_source_sys::GtkSourceCompletionProposal, completion_info: *mut gtk_source_sys::GtkSourceCompletionInfo) {
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.update_info(&from_glib_borrow(completion_provider), &from_glib_borrow(proposal), &from_glib_borrow(completion_info))
}
unsafe extern "C" fn completion_provider_get_start_iter<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider, context: *mut gtk_source_sys::GtkSourceCompletionContext, proposal: *mut gtk_source_sys::GtkSourceCompletionProposal, iter: *mut gtk_sys::GtkTextIter) -> glib_sys::gboolean{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_start_iter(&from_glib_borrow(completion_provider), &from_glib_borrow(context), &from_glib_borrow(proposal), &from_glib_borrow(iter)).to_glib()
}
unsafe extern "C" fn completion_provider_activate_proposal<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider, proposal: *mut gtk_source_sys::GtkSourceCompletionProposal, iter: *mut gtk_sys::GtkTextIter) -> glib_sys::gboolean{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.activate_proposal(&from_glib_borrow(completion_provider), &from_glib_borrow(proposal), &from_glib_borrow(iter)).to_glib()
}
unsafe extern "C" fn completion_provider_get_interactive_delay<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> libc::c_int{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_interactive_delay(&from_glib_borrow(completion_provider))
}
unsafe extern "C" fn completion_provider_get_priority<T: ObjectSubclass + CompletionProviderImpl>(completion_provider: *mut gtk_source_sys::GtkSourceCompletionProvider) -> libc::c_int{
let instance = &*(completion_provider as *mut T::Instance);
let imp = instance.get_impl();
imp.get_priority(&from_glib_borrow(completion_provider))
} |
Correct based on what you found :)
It's unsafe to return something with See this here for an example how to ensure this is all safe: https://github.com/gtk-rs/gio/blob/master/src/subclass/io_stream.rs#L127
There it is not a problem because the Rust code keeps the reference alive. It's the difference between borrowing a parameter to a function or having a function return a reference.
No worries, you're not asking that many questions actually :)
You only would have to implement the functions that are mandatory, and the optional ones that you need yourself. But even better if you implemented all :) See above for the |
You mentioned that I don't need to implement anything for non-mandatory functions. This interface seems to have a few such functions. Two of them, |
Also, in your examples, the interfaces return values aren't nullable. But, in the interface that I want to use, they are. Thus, my |
You could provide a default implementation for them that behaves correctly
Something like that, yes. Or |
Is there some easy way to have it forward to the default C implementation in this case? |
I've added in the logic for making these functions safe. The complete file is here (it's getting long enough to be unwieldy to pass around in comments). |
I've gotten far enough along to attempt to make a subclass. I have this so far, but rustc complains about a variety of traits not being implemented on What I have: struct CustomAutocomplete;
impl ObjectSubclass for CustomAutocomplete{
const NAME: &'static str = "CustomAutocomplete";
type ParentType = sourceview::CompletionProvider;
type Instance = glib::subclass::simple::InstanceStruct<Self>;
type Class = glib::subclass::simple::ClassStruct<Self>;
glib::glib_object_subclass!();
fn type_init(type_: &mut glib::subclass::InitializingType<Self>){
type_.add_interface::<CompletionProvider>();
}
fn new() -> Self{
CustomAutocomplete
}
}
impl ObjectImpl for CustomAutocomplete{
glib::glib_object_impl!();
}
impl sourceview::CompletionProviderImpl for CustomAutocomplete{
fn get_name(&self, obj: &CompletionProvider) -> GString {
unimplemented!()
}
fn get_icon(&self, obj: &CompletionProvider) -> Option<gdk_pixbuf::Pixbuf> {
unimplemented!()
}
fn get_icon_name(&self, obj: &CompletionProvider) -> Option<GString> {
unimplemented!()
}
fn get_gicon(&self, obg: &CompletionProvider) -> Option<gio::Icon> {
unimplemented!()
}
fn populate(&self, obg: &CompletionProvider, context: &sourceview::CompletionContext) {
unimplemented!()
}
fn get_activation(&self, obg: &CompletionProvider) -> sourceview::CompletionActivation {
unimplemented!()
}
fn provide_match(&self, obg: &CompletionProvider, context: &sourceview::CompletionContext) -> bool {
unimplemented!()
}
fn get_info_widget(&self, obg: &CompletionProvider, proposal: &sourceview::CompletionProposal) -> Option<gtk::Widget> {
unimplemented!()
}
fn update_info(&self, obg: &CompletionProvider, proposal: &sourceview::CompletionProposal, info: &CompletionInfo) {
unimplemented!()
}
fn get_start_iter(&self, obg: &CompletionProvider, context: &sourceview::CompletionContext, proposal: &sourceview::CompletionProposal, iter: >k::TextIter) -> bool {
unimplemented!()
}
fn activate_proposal(&self, obg: &CompletionProvider, proposal: &sourceview::CompletionProposal, iter: >k::TextIter) -> bool {
unimplemented!()
}
fn get_interactive_delay(&self, obj: &CompletionProvider) -> i32 {
unimplemented!()
}
fn get_priority(&self, obg: &CompletionProvider) -> i32 {
unimplemented!()
}
} Rustc's error: error[E0277]: the trait bound `(): gio::subclass::IsSubclassable<CustomAutocomplete>` is not satisfied
--> examples/custom_autocompletion_subclass.rs:46:5
|
46 | glib::glib_object_subclass!();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `gio::subclass::IsSubclassable<CustomAutocomplete>` is not implemented for `()`
|
::: /home/david/.cargo/git/checkouts/glib-928cf7b282977403/d322eaf/src/subclass/types.rs:460:71
|
460 | <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,
| ----------------- required by this bound in `glib::subclass::register_type`
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) |
If there is one, sure. Is there? You can find an example of that here.
It's an interface, you can't use that as parent type. You can use |
After changing the parent type, that specific error goes away, but a new one comes up. Here's rustc's full error message: error[E0277]: the trait bound `CustomAutocomplete: glib::IsA<sourceview::CompletionProvider>` is not satisfied
--> examples/custom_autocompletion_subclass.rs:29:27
|
29 | .add_provider(&completion);
| ^^^^^^^^^^^ the trait `glib::IsA<sourceview::CompletionProvider>` is not implemented for `CustomAutocomplete`
error[E0599]: no function or associated item named `static_type` found for struct `CustomAutocomplete` in the current scope
--> examples/custom_autocompletion_subclass.rs:41:33
|
37 | struct CustomAutocomplete;
| --------------------------
| |
| function or associated item `static_type` not found for this
| doesn't satisfy `CustomAutocomplete: glib::StaticType`
...
41 | glib::Object::new(Self::static_type(), &[])
| ^^^^^^^^^^^ function or associated item not found in `CustomAutocomplete`
|
= note: the method `static_type` exists but the following trait bounds were not satisfied:
`CustomAutocomplete: glib::StaticType`
which is required by `&CustomAutocomplete: glib::StaticType`
`CustomAutocomplete: glib::StaticType`
which is required by `&mut CustomAutocomplete: glib::StaticType`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `static_type`, perhaps you need to implement it:
candidate #1: `glib::StaticType`
error[E0277]: the trait bound `CustomAutocomplete: glib::IsA<glib::Object>` is not satisfied
--> examples/custom_autocompletion_subclass.rs:43:14
|
43 | .downcast()
| ^^^^^^^^ the trait `glib::IsA<glib::Object>` is not implemented for `CustomAutocomplete`
|
= note: required because of the requirements on the impl of `glib::object::CanDowncast<CustomAutocomplete>` for `glib::Object`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `sourceview`.
To learn more, run the command again with --verbose. |
You don't implement any of these traits. This is exactly what the |
So, I have a working implementation, but I need to flout Rust's safety rules in order to make it work, and the C APIs pitch a fit of warnings in the console log when doing so, which definitely needs to be fixed. It seems like the issue is with the fn get_info_widget(
&self,
obg: &CompletionProvider,
proposal: &sourceview::CompletionProposal,
) -> Option<gtk::Widget> {
let label = gtk::Label::new(Some(match proposal.get_label() {
Some(ref label_text_gstring) => label_text_gstring.as_str(),
None => "",
}));
Some(label.upcast::<gtk::Widget>())
} Clearly, however, this implementation will give a new The console spam when I comment out the safety checks in the trampoline function:
|
In what sense?
Yes, it must be the same every time, it must stay alive for as long as your instance is alive, and your trampoline function must ensure that.
I'd need a runnable example that reproduces this case, then I can take a look. This looks to me however like the returned widget from that function is not ensured to be kept alive. |
I put the working example on my fork here. To run it, clone the entire repository then run |
That's even more complicated then. You somehow need to ensure that the widget stays alive as long as the completion proposal it belongs to does. For this you'd need to go for example via So your problem is most likely that you don't ensure that it stays around at all. The warnings will probably disappear if you use |
I think that my contribution is ready. I've created a PR.
…On Thu, May 28, 2020, 11:12 AM Sebastian Dröge ***@***.***> wrote:
That's even more complicated then. You somehow need to ensure that the
widget stays alive as long as the completion proposal it belongs to does.
For this you'd need to go for example via g_object_add_weak_notify() to
get notified when the proposal is destroyed.
So your problem is most likely that you don't ensure that it stays around
at all. The warnings will probably disappear if you use to_glib_full()
instead of to_glib_none().0 when returning? You'll just leak all the
widgets then.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#131 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA6MJIKPIC7YYHDBMM4552LRT2EO5ANCNFSM4NF3QBCA>
.
|
I'm currently trying to use this crate in a project that needs heavy-duty source code editing. Part of that is a basic auto-complete implementation. It needs to be a bit more context-sensitive than the current words-based implementation, but not by much. I've decided what algorithms I want to use to do the actual completion, but getting the library to call my code to do the completion and present it to the user seems to currently be impossible. As such, this is a feature request to add the necessary API hooks to make that happen.
While only adding the necessary traits as described in the linked issue is one way of adding this support, ideally, a subclass or interface implementation would not be needed to use these features, as those techniques are cumbersome with GObject in general, but, it would seem, especially so in Rust since one must not only deal with GObject (which is as cumbersome as any C API), but must also deal with the intricacies of the binding at the same time.
As such, I propose a different interface where there is a simple trait that the user can implement, and then pass a
dyn
object to the Rust bindings to act in a similar way as the GObject interface, but where it is significantly easier to use because Rust has built-in support for implementing traits. This could be implemented via adding those traits, then creating a Rust implementation that has aBox<dyn TheTraitThatIJustMentioned>
as a member.While I am willing to attempt this addition myself and PR it, I don't think that I'm the best person to do that. I'm currently new to Rust, GTK/GObject, and these bindings (I've never even used Rust's FFI support), so if I were to do it it would likely have many errors, if I could get it working at all. I do have significant experience with other tools though, such as C without GObject, C++, and some minimal assembly (I once had to write some assembly to call C functions and be called as a C function, without the aid of a compiler, so I am familiar with how FFI probably works despite the fact that I haven't looked into it.).
The text was updated successfully, but these errors were encountered: