Skip to content
This repository was archived by the owner on Mar 1, 2019. It is now read-only.

Conversation

vhdirk
Copy link
Collaborator

@vhdirk vhdirk commented Jun 5, 2018

Let's start off with the action interface, since that one is used by application at some point.
This generated file is not at all usable yet, but let's see where we get from here.

iface_data: glib_ffi::gpointer
) {
callback_guard!();
let action_iface = &mut *(iface as *mut ffi::);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing the C interface struct type here after ffi::


unsafe extern "C" fn action_get_type<T: ObjectType>(
type_: glib_ffi::GType
) -> glib::Type {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is not needed for interfaces, what you basically have here is a trampoline calling a get_type function on the interface... but there is none on GAction

let interface_static = &*(ptr as *const T::InstanceStructType);
let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
imp.get_state_type()
Copy link
Member

@sdroege sdroege Jun 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like signal trampolines, this needs all the conversion stuff for the return value (from_glib_full in this case) and also the parameters (none here). You also want to pass the &gio::Action via &from_glib_borrow(ptr) to this and all other functions

let interface_static = &*(ptr as *const T::InstanceStructType);
let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
imp.change_state()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you want to pass both ptr and value to the function, which should work the same as in signal trampolines


pub trait ActionImpl: AnyImpl + 'static {

fn activate(&self, action: &T, parameter: Option<&glib::Variant>);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The &T here should be a &gio::Action AFAIU

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. I was thinking for a moment that we could make actionImpl generic over T? But i'm not sure if that has any benefits to it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That has the problem that you can't use Box<ActionImpl> anymore but have to provide the type parameter everywhere, or not?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. I can't even remember why I wanted to make it generic

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not do that for now then :) It can always be dynamically casted if needed

@sdroege
Copy link
Member

sdroege commented Jun 5, 2018

Looks generally very good, the main thing missing here at this point seems to be the type conversion between C and Rust, which should be the same as in the signal trampolines

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 6, 2018

Aside from missing imports and so on, the largest issue remains those trampolines. I've been looking at the signals implementation, but I can only find stuff marked as TODO :)

@sdroege
Copy link
Member

sdroege commented Jun 7, 2018

I've been looking at the signals implementation, but I can only find stuff marked as TODO :)

There's https://github.com/gtk-rs/gir/blob/master/src/codegen/trampoline.rs, specifically the trampoline_call_func function. trampoline_call_parameters is converting all the parameters from C to Rust, analysis.ret.trampoline_to_glib converts the return value back to C.

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 7, 2018

Thanks. I'm not sure how correct this is, but it seems like it could work

let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
let wrap: T = from_glib_borrow(instance);
imp.activate(&wrap, &from_glib_none(action), /*Unknown conversion*/parameter)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be &from_glib_borrow(action) (and IIRC would be for signals). Not sure why it falls apart on the GVariant, in the function just below it works :)

Copy link
Member

@sdroege sdroege Jun 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally this should do &from_glib_borrow for all shared/boxed/object types (if transfer none) like it would in signal trampolines. There's probably a code path that has to be enabled for your case too here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, all of the 'action' conversions here are incorrect. That's what 'wrap' is

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Indeed

let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
let wrap: T = from_glib_borrow(instance);
imp.get_name(&wrap, &from_glib_none(action))/*Not checked*/.to_glib_none().0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value is unsafe but that's because the C API is broken, this needs a manual implementation.

You need to return a string here that is valid for the whole lifetime of the underlying action object

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@federicomenaquintero things like this are btw examples why I think we will need an override system somewhere between gnome-class and the .gir files, and why I believe the trampolines and some glue infrastructure should live in the gtk/etc bindings for gnome-class to use.

I have some more examples in GStreamer :) We should talk about this at the next hackfest in more detail

let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
let wrap: T = from_glib_borrow(instance);
imp.get_parameter_type(&wrap, &from_glib_none(action))/*Not checked*/.to_glib_none().0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for the name

let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
let wrap: T = from_glib_borrow(instance);
imp.get_state(&wrap, &from_glib_none(action)).to_glib_full()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return value could use an optimization but not important right now

let ret = imp.get_state(...);
let ptr = ret.to_glib_none().0;
mem::forget(ret);
ptr

let imp = instance.get_impl();
let imp = (*(*interface_static).imp_static).get_impl(imp);
let wrap: T = from_glib_borrow(instance);
imp.get_state_type(&wrap, &from_glib_none(action))/*Not checked*/.to_glib_none().0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same problem as for name

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 7, 2018

As far as the gir is concerned, I don't think I can manage to fix the c-api broken-ness. So either I fix that manually, or we come up with a plan to pull implementations from a separate file.
Even though I like the ambition of the latter, I'd like to have something to work with. Who knows what else needs fixing, so I guess using the gir to generate a skeleton and going from there is more feasible

@sdroege
Copy link
Member

sdroege commented Jun 8, 2018

So either I fix that manually, or we come up with a plan to pull implementations from a separate file.

Generally I was thinking separate files should work fine, e.g. marking a vfunc as ignore in the toml file and then having one file per vfunc that defines the 3 parts of it: 1) the trait function signature, 2) the chaining up part, 3) the trampoline. And then during code generation, those parts are spliced into the output.

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 8, 2018

Do you have any proposition regarding the syntax of that file? I'd like to make it as simple as possible to know what content to splice where. Ideally, the gir should not know about what's in that file, only which block to insert where.

@sdroege
Copy link
Member

sdroege commented Jun 8, 2018

Do you have any proposition regarding the syntax of that file? I'd like to make it as simple as possible to know what content to splice where. Ideally, the gir should not know about what's in that file, only which block to insert where.

Yes I agree, ideally we wouldn't need to parse it at all. So maybe just separate files with the actual content that is inserted in the relevant places? manual/action_vfuncname_trampoline.custom, etc?

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 8, 2018

Something like this? (see gir for implementatin details)

@sdroege
Copy link
Member

sdroege commented Jun 8, 2018

Yes, exactly that :)

@sdroege
Copy link
Member

sdroege commented Jun 9, 2018

diff --git a/gio-subclass/src/action.rs b/gio-subclass/src/action.rs
index 7542553..9a6a927 100644
--- a/gio-subclass/src/action.rs
+++ b/gio-subclass/src/action.rs
@@ -78,9 +78,9 @@ unsafe extern "C" fn action_activate<T: ObjectType>
     let param = if parameter.is_null(){
         None
     }else{
-        Some(&from_glib_none(parameter))
+        Some(from_glib_none(parameter))
     };
-    imp.activate(&wrap, param)
+    imp.activate(&wrap, param.as_ref())
 }
 
 unsafe extern "C" fn action_change_state<T: ObjectType>
@@ -206,7 +206,7 @@ unsafe extern "C" fn action_init<T: ObjectType>(
     iface_data: glib_ffi::gpointer
 ) {
     callback_guard!();
-    let action_iface = &mut *(iface as *mut gio_ffi::GAction);
+    let action_iface = &mut *(iface as *mut gio_ffi::GActionInterface);
     let iface_type = (*(iface as *const gobject_ffi::GTypeInterface)).g_type;
     let type_ = (*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type;
     let klass = &mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct<T>);

This is required to make it compile. Wrong type is used for the interface, and some lifetime issues with a variable

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 9, 2018

Thanks!

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 9, 2018

So while this thing now compiles, I have no idea how to use it. I'd guess we need SimpleAction or so in order to test this?

@sdroege
Copy link
Member

sdroege commented Jun 10, 2018

No, SimpleAction already implements the GAction interface. We'd need a new GObject and then can have it implement the interface. I'll write a compiling-but-not-working example for that later (because I don't know how GAction is supposed to be used properly) :)

@sdroege
Copy link
Member

sdroege commented Jun 10, 2018

You can find an example that compiles here. Let me know if you have any questions about the code, and also note the function I've added to action.rs

@sdroege
Copy link
Member

sdroege commented Jun 13, 2018

Were you able to write a subclass of GAction that is actually doing something meaningful?

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jun 13, 2018

No. Not yet. I don't know what to do with that one either :)

@sdroege
Copy link
Member

sdroege commented Jun 13, 2018

Ah, I thought you started with GAction because that's something you actually needed :) I guess look at the implementation of GSimpleAction in gio then

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jul 4, 2018

I've regenerated one last time. It now includes some let rs_ret statements. That's because I've been tailoring the gir to support writing back output parameters to pointers. I'll get a PR using that specifically up soon.

@sdroege
Copy link
Member

sdroege commented Jul 4, 2018

Ok, go for it then :)

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jul 4, 2018

Ready for merge?

@sdroege
Copy link
Member

sdroege commented Jul 4, 2018

Yes, but please don't forget to look at the property flag stuff afterwards :)

@vhdirk
Copy link
Collaborator Author

vhdirk commented Jul 4, 2018

I'll do that soon. I'll need it anyway.

@vhdirk vhdirk merged commit bc0d24f into gtk-rs:master Jul 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants