widgetgtksubclassglade

Make known subclassed wigets in .ui files in GTK+


I was looking in the GNOME Calendar application, and the gcal-window.ui file has this line (on 292) in it:

<object class="GcalQuickAddPopover" id="quick_add_popover">

And in the same directory that the gcal-window ui, source code, and header files were in, there is the file that defines the GcalQuickAddPopover. What are the rules for making the .ui files knowing which object are in existence, and which are not. If I deleted the gcal-quick-add-popover file, how would it know or not know that it is there?


Solution

  • The types that can be used inside a GtkBuilder UI definition are the ones registered at run-time before the XML is parsed (typically by calling gtk_builder_new or similar).

    Here is a self-contained example that shows that.

    /* cc ui.c -o ui $(pkg-config --cflags --libs gtk+-3.0) */
    
    #include <gtk/gtk.h>
    
    
    /* Define new type (MyCustomLabel) */
    
    #define MY_TYPE_CUSTOM_LABEL my_custom_label_get_type()
    struct _MyCustomLabel { GtkLabel label; };
    
    G_DECLARE_FINAL_TYPE(MyCustomLabel, my_custom_label, MY, CUSTOM_LABEL, GtkLabel)
    G_DEFINE_TYPE(MyCustomLabel, my_custom_label, GTK_TYPE_LABEL)
    
    static void
    my_custom_label_class_init(MyCustomLabelClass *cls)
    {
    }
    
    static void
    my_custom_label_init(MyCustomLabel *label)
    {
        gtk_label_set_label(GTK_LABEL(label), "This is my custom label");
    }
    
    
    /* Test case */
    
    static const gchar *ui =
        "<interface>"
            "<object id='W' class='GtkWindow'>"
                "<child>"
                    "<object class='MyCustomLabel'/>"
                "</child>"
            "</object>"
        "</interface>";
    
    
    int main()
    {
        GtkBuilder *builder;
        GtkWidget *window;
    
        gtk_init(NULL, NULL);
    
        /* Ensures that MyCustomLabel has been registered with the type
         * system. Without this call, the application crashes when parsing
         * `ui`, i.e. at the `gtk_builder_new_from_string` call. */
        g_type_ensure(MY_TYPE_CUSTOM_LABEL);
    
        builder = gtk_builder_new_from_string(ui, -1);
        window = GTK_WIDGET(gtk_builder_get_object(builder, "W"));
        g_object_unref(builder);
    
        gtk_widget_show_all(window);
        gtk_main();
    
        return 0;
    }
    

    See the GObject documentation for more details on how the type system works.