Search code examples
ctemplatesgtkbuildergtk4

Create your own class from a template with GTK4, C and XML


I'm trying to test the example from the GNOME Developer Documentation.

https://developer.gnome.org/documentation/tutorials/widget-templates.html

But I seem to be doing something wrong, because I get the error message:

_myWidget:11427): Gtk-WARNING **: 15:16:35.255: Trying to snapshot GtkEntry 0x55ac0c7d7650 without a current allocation

(_myWidget:11427): Gtk-WARNING **: 15:16:35.255: Trying to snapshot GtkButton 0x55ac0c7b7b40 without a current allocation

widget-class.c

#include <gtk/gtk.h>

// own class with button and entry
// Add the template registration to your class_init function

G_DECLARE_FINAL_TYPE (ExampleWidget, example_widget, EXAMPLE, WIDGET, GtkWidget)

#define EXAMPLE_TYPE_WIDGET (example_widget_get_type ())   

struct _ExampleWidget
{
  GtkWidget parent_type;
  GtkWidget *entry;
  GtkWidget *button;
};

G_DEFINE_TYPE (ExampleWidget, example_widget, GTK_TYPE_WIDGET)

//Clear the template children when disposing the widget instance
static void
example_widget_dispose (GObject *gobject)
{
  gtk_widget_dispose_template (GTK_WIDGET (gobject), EXAMPLE_TYPE_WIDGET);
  G_OBJECT_CLASS (example_widget_parent_class)->dispose (gobject);
}

static void
example_widget_class_init (ExampleWidgetClass *klass)
{
  G_OBJECT_CLASS (klass)->dispose = example_widget_dispose;
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  gtk_widget_class_set_template_from_resource (widget_class,"/Prog/widget.ui");

  //Bind the widgets defined inside the template file to the corresponding 
  //members of the widget’s instance data structure
  gtk_widget_class_bind_template_child (widget_class, ExampleWidget, entry);
  gtk_widget_class_bind_template_child (widget_class, ExampleWidget, button);

}

//Initialize the template children when initializing the widgdet instance
static void
example_widget_init (ExampleWidget *self)
{
  gtk_widget_init_template (GTK_WIDGET (self));

  // It is now possible to access self->entry and self->button
}

static GtkWidget * example_widget_new(void)   
{
    ExampleWidget *widget = g_object_new(EXAMPLE_TYPE_WIDGET,NULL);
    return GTK_WIDGET(widget);   
} 

/****************************************************************/

static void activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;

    window = gtk_application_window_new(app);
    //The example widget is created and installed here
    GtkWidget *widget_1 = example_widget_new();

    gtk_window_set_child(GTK_WINDOW(window),GTK_WIDGET(widget_1));
    gtk_window_present(GTK_WINDOW (window));
}

int main (int argc, char **argv)
{
    GtkApplication *app;
    int status;
    app = gtk_application_new ("org.gtk.examplewidget", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate",G_CALLBACK(activate),NULL);
    status = g_application_run (G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}

widget.ui

<interface>
  <template class="ExampleWidget" parent="GtkWidget">
    <child>
      <object class="GtkEntry" id="entry">
      </object>
    </child>
    <child>
      <object class="GtkButton" id="button">
        <property name="label">Hello</property>
      </object>
    </child>
  </template>
</interface>

resource.xml

<gresources>
        <gresource prefix="Prog">
                <file preprocess= "xml-stripblanks">widget.ui</file>
        </gresource>
</gresources>

Does anyone have any idea where the problem might be?


Solution

  • After some research and trial and error, especially with the help of the question Writing a Custom GTK widget with template UI files I've found the solution. In the example I'm using, the layout manager is missing. For this purpose, the following additions were necessary in the class_init function:

    static void
    example_widget_class_init (ExampleWidgetClass *klass)
    {
     ...
    
      gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); 
    
    }
    

    enter image description here