The „create_layout_child“ function is not called in the Layout Manager. GTK4 with C

While trying out the possibilities of the GtkLayoutManager, I tried to use the “create_layout_child” function. According to the documentation, you should create your own instance of GtkLayoutManager for this purpose. “Create_layout_child” should then be overwritten as a virtual function. It will then be called automatically. Accordingly, I’ve created a derived class from GtkLayoutManager. It’s all working now too, but the “create_layout_child” function isn’t called, so I can’t use it. Does anyone have an idea or hint on how to implement this feature?

My layout manager looks like this.

#include"layout_mywidget.h"

struct _LayoutMywidget
{
    GtkLayoutManager parent_instance;
};

struct _LayoutMywidgetClass
{
    GtkLayoutManagerClass parent_class;
};

G_DEFINE_TYPE (LayoutMywidget, layout_mywidget, GTK_TYPE_LAYOUT_MANAGER)

static GtkLayoutChild *
layout_mywidget_create_layout_child (GtkLayoutManager *layout_manager,
                                     GtkWidget        *widget,
                                     GtkWidget        *child)
{
    //Function is not called. Why?
    g_print("layout_child\n");
}

/* Container */
static void layout_mywidget_measure (GtkLayoutManager *layout_manager,
                                     GtkWidget      *widget,
                                     GtkOrientation orientation,
                                     int            for_size,
                                     int            *minimum,
                                     int            *natural,
                                     int            *minimum_baseline,
                                     int            *natural_baseline)
{
     /* Already set in widget.ui   */
};

/*Position of the children*/
static void layout_mywidget_allocate (GtkLayoutManager *layout_manager,
                                      GtkWidget         *widget,
                                      int                width,
                                      int                height,
                                      int                baseline)
{
    GtkRequisition label_req;
    GtkRequisition entry_req;
    GtkRequisition button_req;

    GtkWidget *child;

    for(child = gtk_widget_get_first_child(widget);
            child != NULL;
            child = gtk_widget_get_next_sibling (child))
    {
    
        if(strcmp(gtk_widget_get_name(child),"GtkEntry") == 0)
        {
            gtk_widget_get_preferred_size(child, &entry_req,NULL);
            gtk_widget_size_allocate(child,
            &(const GtkAllocation){10,60,200,entry_req.height},-1);
        }
        else if (strcmp(gtk_widget_get_name(child),"GtkLabel") == 0)
        {
            gtk_widget_get_preferred_size(child, &label_req,NULL);
            gtk_widget_size_allocate(child,
            &(const GtkAllocation){width/2-(label_req.width/2),20,
            label_req.width,label_req.height},-1);
        }
        else if (strcmp(gtk_widget_get_name(child),"GtkButton") == 0)
        {
            gtk_widget_get_preferred_size(child, &button_req,NULL);
            gtk_widget_size_allocate(child,
            &(const GtkAllocation){220,60,button_req.width,
            button_req.height},-1);
        }
    
    }
};

/* The default implementation of this virtual function, which means that the widget 
 * will only ever get -1 passed as the for_size value to its Gtk.WidgetClass.measure 
 * implementation. You can overwrite that */
static GtkSizeRequestMode
layout_mywidget_get_request_mode (GtkLayoutManager *layout_manager,
                                  GtkWidget        *widget)
{
    return GTK_SIZE_REQUEST_CONSTANT_SIZE;
};

static void layout_mywidget_class_init (LayoutMywidgetClass *class)
{
    GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (class);

    layout_class->get_request_mode = layout_mywidget_get_request_mode;
    layout_class->measure = layout_mywidget_measure;
    layout_class->allocate = layout_mywidget_allocate;
    //Function is not called.  Why ?
    layout_class->create_layout_child = layout_mywidget_create_layout_child;
};

static void layout_mywidget_init(LayoutMywidget *self)
{
};

GtkLayoutManager *layout_mywidget_new(void)
{
    return g_object_new(LAYOUT_TYPE_MYWIDGET,NULL);
};

grafik

The create_layout_child() is called by gtk_layout_manager_get_layout_child().

You’re supposed to call gtk_layout_manager_get_layout_child() whenever you need to set or retrieve a layout property; for instance, this is what GtkGrid does:

void
grid_attach (GtkGrid *grid,
             GtkWidget *widget,
             int column,
             int row,
             int width,
             int height)
{
  GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
  GtkGridLayoutChild *grid_child;

  gtk_widget_set_parent (widget, grid);

  grid_child = gtk_layout_manager_get_layout_child (priv->layout_manager, widget);
  gtk_grid_layout_child_set_column (grid_child, column);
  gtk_grid_layout_child_set_row (grid_child, row);
  gtk_grid_layout_child_set_column_span (grid_child, width);
  gtk_grid_layout_child_set_row_span (grid_child, height);
}

A GtkLayoutChild is an ancillary class for storing data related to the layout of a widget; instances of this class are created only on request, and cached for as long as the widget is a child of a specific parent using a specific layout manager.

Thanks, Is this part of the layout manager?

Is what part of the layout manager?

If your layout manager does not have layout properties, then you don’t need to override the create_layout_child() virtual function.

How do I create such a property in the layout manager.

First of all, you create a subclass of GtkLayoutChild and add the properties to that subclass; for instance, if you created a LayoutMywidget layout manager class, you could use LayoutMychild for the layout child class.

Then, in the class_init of your GtkLayoutManager subclass, you use:

  layout_class->layout_child_type = layout_mychild_get_type ();

This way you don’t need to override create_layout_child() at all.

Then, every time you need to access a layout property, you call gtk_layout_manager_get_layout_child() first to get the LayoutMychild instance, and then call the accessor for the property.

Thanks, for now. I’ll try it ! :slight_smile:

I’m still not getting anywhere.
How to add the properties in the GtkLayoutChild class?

The same way you do for every other GObject class: g_object_class_install_property().

You don’t strictly need a property: you can use the GtkLayoutChild base class and put state variables inside the instance structure; properties make it easier to do things like property bindings and notification.

Thanks! I keep trying. :slight_smile:

Unfortunately I haven’t been successful yet. :confused:
Is there an example somewhere I could look at for this?

The code for GtkGridLayout is a complete example of a layout manager with a custom child layout object: gtk/gtkgridlayout.c · main · GNOME / gtk · GitLab

It does not override GtkLayoutManagerClass.create_layout_child because it specifies the type using GtkLayoutManagerClass.layout_child_type.

At this point, I think you need to learn a lot more about how GObject works, before delving into the deep waters of implementing a new GtkLayoutManager.

Thanks, I’ll work on it :wink: