How to properly add images to buttons?

,

Container widgets acquire a reference on their children when they are added, and release it when the children is removed. If the reference on the child is the last one, the widget gets destroyed.

When creating a new widget, though, the instance is given a “floating” reference; this floating reference is “sunk” by the container, so you can safely do something like:

  gtk_container_add (GTK_CONTAINER (button), gtk_label_new ("I'm a label"));

without leaking the label.

Calling gtk_button_set_image() will remove the current image child widget, and replace it with the one you pass. The first time you call it, the image widget will have the floating reference sunk, and the ownership transferred to the button; the second time, the button will release the reference it has on the old image widget, and acquire it on the new one.

So, what happens is this:

  1. play = gtk_image_new() → play reference count: 1, floating
  2. pause = gtk_image_new() → pause reference count: 1, floating
  3. gtk_button_set_image(play) → play reference count: 1, not floating
  4. gtk_button_set_image(pause) → play reference count: 0, pause reference count: 1, not floating

At this point, play has been destroyed, so your icons->play field points to garbage, and you’ll get a segmentation fault when you call gtk_button_set_image(button, icons->play).

You will need to acquire full ownership of the image widgets, so that they can survive the removal from the button:

  struct Icons icons;

  icons.play = gtk_image_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_BUTTON);
  icons.pause = gtk_image_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_BUTTON);

  g_object_ref_sink (icons.play);
  g_object_ref_sink (icons.pause);

This way, the floating reference will already have been sunk, and gtk_button_set_image() will acquire a real reference on the widget.

Since your icons are going to exist for the duration of the program, you can simply leave them be, and let the OS reclaim the memory used once the process terminates; otherwise, you will need to release the reference you acquired on the widgets explicitly, to avoid a memory leak:

  gtk_main ();

  g_object_unref (icons.play);
  g_object_unref (icons.pause);

  return 0;

For more information:

1 Like