Allow implementing a GAction interface#1640
Conversation
1c5636b to
c4de546
Compare
|
Another issue I have is that I have no clue what would be an idiomatic way to use |
GtkEditable provides a method to automatically add the properties for you along with the get_property and set_property. Either the example implementing a custom Action would have to do that manually or you could add helpers that would do it automatically for you, see the EditableImpl in the gtk4-rs repo. |
|
|
||
| #[derive(glib::Properties, Default)] | ||
| #[properties(wrapper_type = super::RenamedAction)] | ||
| pub struct RenamedAction { |
There was a problem hiding this comment.
The properties macro allows overriding properties by the way
There was a problem hiding this comment.
I gave it a try but received an error
(process:718176): GLib-GObject-CRITICAL **: 22:59:07.010: When installing property: type 'ExampleRenamedAction' already has a property named 'name'
I guess it's because of the sequence of initialization. When I define a class and implement an interface then class installs properties first and interface fails to install them.
There was a problem hiding this comment.
The way how you do it now should work or not?
There was a problem hiding this comment.
It does not work. I guess It works as expected in the cases like
class A implements IFace
class B extends A implements IFace {
override property x of IFace
}
where initialization sequence is: A, IFace, B. So, when B is initializing IFace is already there and could be overriden.
but does not work for
class B implements IFace {
override property x of IFace
}
where initialization sequence is: B, IFace. So, B has nothing to override yet.
There was a problem hiding this comment.
You didn't find a solution to this yet, right? This probably should be solved independent of this PR (please create an issue with all you remember)
c4de546 to
59cbb3a
Compare
|
@bilelmoussaoui Thanks for pointing a direction! Unfortunately Gio does not provide helpers similar to I am not sure if I fully understand the subject but this line seems wrong. Gtk's doc uses |
59cbb3a to
482d8ef
Compare
| glib::ffi::g_free(properties as *mut _); | ||
| let first_prop = first_prop.assume_init() + 1; | ||
|
|
||
| set_first_prop(instance_type, first_prop as usize); |
There was a problem hiding this comment.
That's a nice hack for the properties :)
gio/src/subclass/action.rs
Outdated
| _pspec: &glib::ParamSpec, | ||
| ) -> Option<glib::Value> { | ||
| let type_: glib::Type = self.obj().type_(); | ||
| let property = ActionProperty::from_type(type_, prop_id)?; |
There was a problem hiding this comment.
If you pass in Self::type_() here then you don't need to do all the parent type walking inside from_type() and always have directly the correct type
There was a problem hiding this comment.
That's what I've found in GtkEditable's code.
There was a problem hiding this comment.
@bilelmoussaoui Why does it do things so complicated, do you remember? :)
gio/src/subclass/action.rs
Outdated
| let instance = &*(actionptr as *mut T::Instance); | ||
| let imp = instance.imp(); | ||
|
|
||
| if let Some(parameter_type) = imp.parameter_type() { |
There was a problem hiding this comment.
This should probably be moved into the set_qdata() call. Now you'd get inconsistent behaviour if the function returns Some on the first call and None afterwards
There was a problem hiding this comment.
It's not directly forbidden by Gio's docs, but I think it could be insane if the type of a parameter would change during the action's lifetime.
A similar assumption is made in ActionGroup.
There was a problem hiding this comment.
My personal approach here would be to either only call the function once to don't give the user a chance to do it wrong, or otherwise at least to add an assertion :)
There was a problem hiding this comment.
I've changed this and other places (name, parameter_type and state_type) in the way that the function is called once.
bef560a to
ecae6f6
Compare
ecae6f6 to
066dd78
Compare
| }) | ||
| } | ||
|
|
||
| fn delegate_set_property( |
There was a problem hiding this comment.
good call of adding this even if it just returns false; it would allow adding some attribute to glib::derived_properties to automatically use the delegate_get_property / delegate_set_property calls, simplifying things a bit.
|
what is left to be done here btw? |
I'd say its ready, he-he. But I have a concern about a potential off-by-one error (see above) and waited for your judgement. |
|
It looks good to me as is. Any future improvements can be done in the future without blocking this forever. I will wait for an ack from @sdroege, otherwise i will merge in few days if nothing. |
| } | ||
|
|
||
| fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { | ||
| if !self.delegate_set_property(id, value, pspec) { |
There was a problem hiding this comment.
If multiple interfaces like this are implemented, the method name would probably conflict. Should we write the interface name in the method name (delegate_action_set_property()), or change the example to specify the trait (<Self as ActionImplExt>::delegate_set_property(self, id, value, pspec))?
There was a problem hiding this comment.
So far there are only Actions and Editable.i rather keep it this way until we find more cases like this
There was a problem hiding this comment.
You'd already have this problem then if you implement both interfaces in the same type :)
There was a problem hiding this comment.
There is 0 use case for that. You would rather implement GActionMap instead
There was a problem hiding this comment.
Sure, but if we want to solve this problem later we need to change API in even more places so it seems useful to figure this out from the beginning. I'm not going to block this PR on this though, just don't tell me in a few years that I didn't warn you :P
There was a problem hiding this comment.
My goal is to basically make the derived_properties macro automatically generate those bits for you. I will send a patch for it once this PR lands
| .expect("no parent \"activate\" implementation"); | ||
| func( | ||
| self.obj().unsafe_cast_ref::<Action>().to_glib_none().0, | ||
| parameter.to_glib_none().0, |
There was a problem hiding this comment.
As this is to_glib_none(), maybe the parameter should be a reference (same for others above)
| let parameter: Option<glib::Variant> = from_glib_none(parameterptr); | ||
|
|
||
| imp.activate(parameter); |
There was a problem hiding this comment.
| let parameter: Option<glib::Variant> = from_glib_none(parameterptr); | |
| imp.activate(parameter); | |
| let parameter: Option<glib::Variant> = from_glib_borrow(parameterptr); | |
| imp.activate(parameter.as_ref()); |
or so
| if let Some(first_prop) = get_first_prop(type_) { | ||
| break ActionProperty::from_id(first_prop, id); | ||
| } | ||
| type_ = type_.parent()?; |
There was a problem hiding this comment.
Is this actually correct to look at all the parents, can you add a comment why?
Shouldn't this just look at the just the type of T?
Maybe a test with multiple levels of GAction inheritance would be useful to make sure this works and continues working
| .get_name | ||
| .expect("no parent \"get_name\" implementation"); | ||
| let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0); | ||
| from_glib_none(ret) |
There was a problem hiding this comment.
This is rather suboptimal as it copies strings all the time whenever the name is retrieved. This should be possible to make a &glib::GStr or not?
Co-authored-by: Sebastian Dröge <slomo@coaxion.net>
Closes #1636