-
-
Notifications
You must be signed in to change notification settings - Fork 182
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
Add composite template callback macro #691
Conversation
This is very cool! I have a "UX" question: is the |
210978b
to
dffbca4
Compare
Not quite, but the only other option I could get to work was to make the This is because the |
The is it not possible to do something similar to what the fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
} ? |
This one only works because subclasses have to implement
This could actually be done by making it |
In my opinion it works better, it also mirrors the C api better, Anyways, in the future it can be improved to be automatic. |
There's a lot of black magic I'd like to try using to improve sub-classing, but would require specialization other features that aren't stable/implemented and won't be soon. Unfortunately I don't think there's currently a way to avoid something like this. Personally, I would find it more natural to define callbacks on the wrapper type. I might want to make a function part of the type's public API and also use it as a callback; which I think isn't too uncommon. With the current implementation I'd have to define the function for both types, with one wrapping the other. (It's generally annoying having to deal with a separate private inner type and a wrapper type when sub-classing, but I don't know how that could be avoided.) |
I suppose this could use a rebase so the tests are run after merging the requires ObjectExt::watch_closure? :) |
I've spent some time thinking about this and I'd like to rework it a little bit. My current proposal would be to drop The three macros are distinguished by their handling of the
Here's a sample of how this could work, note the #[gtk::template_callbacks_public]
impl MyWidget {
#[template_callback]
fn button_clicked(&self, button: gtk::Button) {
// ...
}
}
struct CallbackLibrary {}
#[gtk::template_callbacks_library]
impl CallbackLibrary {
#[template_callback]
fn concat(a: &str, b: &str) -> String {
format!("{} {}", a, b)
}
}
mod imp {
#[derive(Debug, Default, CompositeTemplate)]
#[template(file = "mywidget.ui")]
pub struct MyWidget {
// ...
}
#[gtk::template_callbacks_private]
impl MyWidget {
#[template_callback]
fn private_button_clicked(&self, button: gtk::Button) {
// ...
}
}
#[glib::object_subclass]
impl ObjectSubclass for MyWidget {
const NAME: &'static str = "MyWidget";
type Type = super::MyWidget;
type ParentType = gtk::Widget;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
Self::bind_template_callbacks(klass);
Self::Type::bind_template_callbacks(klass);
CallbackLibrary::bind_template_callbacks(klass);
}
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}
} These could also be combined into one macro using attributes if anyone thinks that would work better: // one of these three is required
#[gtk::template_callbacks(public)]
#[gtk::template_callbacks(private)]
#[gtk::template_callbacks(library)] It seems that the public and private distinction could also be removed if either |
Do we need both? |
Before merging this we should also figure out gtk-rs/gtk-rs-core#366 . |
Yes if we want to have callbacks on multiple different structs, with the current implementation as a trait. Possibly that could also be simplified with specialization. |
As you suggested, I would make those the same macro and have an attribute to define whether you want it to be public/private/library that defaults to public which is the most used use case. I wonder if the last use case can be just an attribute on the the functions themselves instead of the whole trait? |
Sure, but only for |
Yes, that would be useful for things like Expressions |
dffbca4
to
17de7d8
Compare
This still needs docs, but has been updated with a new API:
The following are supported as arguments to
The attribute The composite_template example has been updated to make use of each of these. |
In C it is extremely common to cast the last arg ( static void
some_action (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
MyObj *self = MY_OBJ (user_data);
// ...
} I've also rarely seen people use the type outright instead of the static void
some_action (GSimpleAction *action,
GVariant *parameter,
MyObj *self)
{
// ...
}
|
Thinking about this and after giving it a bit of try, i think we should only keep two variants:
|
Well we need to decide that before merging this, or not?
This would be for plain/associated functions that don't take any |
Yes, let's figure out a way to vote for this ?
Yep |
There are lots of websites to set up votes, or we can just do it on Matrix. But as people apparently want to do both variants it seems a bit restrictive to disallow the other completely. We should probably select a default but keep the other possible. |
They are equivalent, it just happens that one will always be a tiny bit more comfortable to use depending on the usecase. I would also prefer to have just one for the sake of simplicity. |
This can't be done with the way the GTK4 API is now, the callbacks are declared during class initialization before any instances exist, and are then invoked from C as part of the What could be done is a dynamic typecheck against the first and last arguments to see if either of them fulfill |
I've just ported Health to use composite template callbacks, that sure made my code a lot nicer! I exclusively used
|
This is needed because the return value is still being constructed when calling this from within the virtual methods of BuilderScope.
Thanks for the testing and feedback! Let's try to improve some of it:
This can't be done safely, it can be done with unsafe, but I'm going to update the docs to clarify some of the behavior here and to match the docs for
Good catch, here's another PR for that: gtk-rs/gtk-rs-core#430
This should actually work, I think it's not working because
Unfortunately the type in the C signal for |
541460e
to
5df54a5
Compare
22507c0
to
f9a0379
Compare
Overall I'm happy with the current situation 🙂 Would be nice to figure out a way to define what could be the default type of the callbacks between subclass/value |
Erm right, was tricked by my own bad naming :D Thanks for the response :) |
55b2d77
to
ff6feb1
Compare
I made a PR to add a trait that removes the need for Tentative changes to this patch are here: f2a7b65 |
ff6feb1
to
da0911b
Compare
Thanks @jf2048 for your work & everyone for their reviews! If there's something else you would like to see improved/fixed please open a new issue / merge request. |
I really can't wait for release with this PR merged. It's so hard to live without this feature after GTK with Python or Vala |
Fixes #24, also fixes part 3 of #77. Depends on gtk-rs/gtk-rs-core#338.
While getting to this work, I noticed that calling
Builder::current_object
while insidecreate_closure
caused GTK to crash becausefrom_glib_none
has consumed the floating reference. I changedcurrent_object
to a manual implementation that callsg_object_ref
viaclone
, and that fixes it. Long-term it seems thatBuilderScopeImpl
should probably be an unsafe trait since all its methods are able to get access to the builder while the object is being constructed.