-
-
Notifications
You must be signed in to change notification settings - Fork 126
Allow implementing a GAction interface #1640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The properties macro allows overriding properties by the way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way how you do it now should work or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I've found in GtkEditable
's code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'd already have this problem then if you implement both interfaces in the same type :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is 0 use case for that. You would rather implement GActionMap instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
.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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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