How do I use the "object" attribute of the <signal> builder tag?

Right now I’ve got my signal set up with just the “name” and “handler” objects set up. My gpointer user_data seems to default to passing the parent window so I’ve just been selecting the member of the window to pass along from the callback:

<!-- window.ui, many properties and siblings omitted -->
<interface>
    <template class="NumsAppWindow" parent="GtkApplicationWindow">
        <child>
            <object class="GtkBox" ...>
                <child>
                    <object class="GtkGrid" ..>
                        <child>
                            <object id="token_decimal" class="GtkButton">
                                <signal name="clicked" handler="decimal_pressed"/>

With the handler being:

static void
decimal_pressed(GtkWidget* w, gpointer p)
{
    NumsAppWindow* window = NUMS_APP_WINDOW(p);
    nums_display_append_decimal(&window->display);
}

I’d rather just pass the display member as the user data to the signal handler using the “object” attribute but I can’t find an example of how to do so.

<signal
    name="clicked"
    handler="decimal_pressed"
    object="????"/>

Hi, unfortunately you cannot do that. The object attribute must be set to the id of another object in the XML because it is bound permanently to the signal handler on object creation. It is not able to bind to properties.

But if “display” is another widget in the XML file then you could set an id on it and then use that as your object.

Good to know! My display IS an object in the xml file but it is listed as a label even though it is a composite struct:

<object class="GtkBox" ...>
  <child>
    <object class="GtkLabel" id="display">

…and the source code:

struct nums_display {
    GtkLabel* screen;
    char buffer[MAXBUFF];
};

struct _NumsAppWindow {
    GtkApplicationWindow parent;
    struct nums_display display;
};
/* snip */
static void
nums_app_window_class_init(NumsAppWindowClass* class)
{
    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class),
            "/app/id/nums/window.ui");
    gtk_Widget_class_bind_template_child(GTK_WIDGET_CLASS(class),
        NumsAppWindow, display);

    gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class),
        decimal_pressed);
}

It felt kind of weird doing it that way but it works (maybe only accidentally and for now…). I thought I read that GTK relies heavily on “first member polymorphism” or something like that. Anyway, before I posted I tried linking the signal handler with object="display" but it threw a runtime error because it wasn’t actually a Label. I think. Sorry, this is a big learning experience for me.

What you have in the C code does not have any effect on it, the value of display is taken from within the XML file. So it just retrieves the GtkLabel and then binds the handler.

The binding of those ids to fields in the C struct happens later in a separate step after all the signal handlers are connected. The reason your call to gtk_widget_class_bind_template_child works is because a GtkLabel happens to be the first member of that struct. To make it more explicit, or to bind to some other field in an internal struct, you could do something like:

gtk_widget_class_bind_template_child_full (
  GTK_WIDGET_CLASS (klass),
  "display",
  FALSE,
  G_STRUCT_OFFSET (NumsAppWindow, display.screen)
);
1 Like

Thank you very much! After your response last night I found these functions and was looking for examples on their use. I thought I would be using the “internal” version of the function but I guess it would just call the “full” version anyway.

I really appreciate your help!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.