Search code examples
cgtk3gtk2

How to pack widgets in a gtk_dialog window using gtk3


In gtk2 the following code snippet works to pack widgets into a gtk_dialog window, using the vbox and action_area of the GtkDialog structure:

  window=gtk_dialog_new();
  gtk_container_set_border_width((GtkContainer *)window, 0);

  scrolled_window=gtk_scrolled_window_new(NULL,NULL);
  gtk_container_set_border_width((GtkContainer *)scrolled_window, 10);
  gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)scrolled_window, GTK_SHADOW_IN);
  gtk_scrolled_window_set_policy((GtkScrolledWindow *)scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_box_pack_start((GtkBox *) (GtkDialog *)window->vbox), scrolled_window, TRUE, TRUE, 0);
  gtk_widget_show(scrolled_window);

  label=gtk_label_new(text);
  gtk_label_set_use_markup((GtkLabel *)label, TRUE);

  gtk_label_set_selectable((GtkLabel *)label, TRUE);
  gtk_label_set_line_wrap((GtkLabel *)label, FALSE);
  gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *)scrolled_window, label);
  gtk_widget_show(label);

  button=gtk_button_new_with_label("close");
  g_signal_connect_swapped(button, "clicked", G_CALLBACK (gtk_widget_destroy), window);

  gtk_widget_set_can_default(button, TRUE);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)window->action_area), button, TRUE, TRUE, 0);

  gtk_widget_grab_default(button);
  gtk_widget_show (button);

  gtk_widget_show(window);

However in gtk3 this is not completely valid code any more. And it will not compile.

If I replace instances of:

(GtkBox *) (GtkDialog *)window->vbox

with:

(GtkBox *) (GtkDialog *)window

And do the same with instances of action_area the code will compile but the window will not show the extra packed widgets, just the ones the dialog comes with by default.

More information, which to me is a bit contradictory https://developer.gnome.org/gtk3/stable/GtkDialog.html#GtkDialog-struct

The GtkDialog contains only private fields and should not be directly accessed.

But when I read this on the same page it seems to contradict the previous quote https://developer.gnome.org/gtk3/stable/GtkDialog.html#gtk-dialog-add-action-widget

If you want to add a non-activatable widget, simply pack it into the action_area field of the GtkDialog struct.

Earlier in that document it states under GtkDialog as GtkBuildable

The GtkDialog implementation of the GtkBuildable interface exposes the vbox and action_area as internal children with the names “vbox” and “action_area”.

But I don't really know how to do that using the GtkBuildable interface neither do I want to. Or perhaps that is exactly what I did in gtk2 and it stopped working in gtk3...?

My question is how can I convert the gtk2 code to work with gtk3 with as few changes as possible. I have been searching for quite a while but found no answer yet. The existing gtk3 documentation leaves me going in circles. Maybe I just miss something totally obvious. Or perhaps you are not supposed to do this anymore and have to use a window instead of a dialog?

Thanks to the answer below I was able to change the code to this working one, it will also eliminate a deprecated warning about gtk_dialog_get_action_area() by using gtk_dialog_add_button()

window=gtk_dialog_new();
gtk_container_set_border_width((GtkContainer *)window, 0);

scrolled_window=gtk_scrolled_window_new(NULL,NULL);
gtk_container_set_border_width((GtkContainer *)scrolled_window, 10);
gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)scrolled_window, GTK_SHADOW_IN);
gtk_scrolled_window_set_policy((GtkScrolledWindow *)scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

gtk_box_pack_start((GtkBox *) (GtkDialog *) (gtk_dialog_get_content_area(window)), scrolled_window, TRUE, TRUE, 0);
gtk_widget_show(scrolled_window);

label=gtk_label_new(text);
gtk_label_set_use_markup((GtkLabel *)label, TRUE);

gtk_label_set_selectable((GtkLabel *)label, TRUE);
gtk_label_set_line_wrap((GtkLabel *)label, FALSE);
gtk_container_add((GtkContainer *)scrolled_window, label);
gtk_widget_show(label);

button=gtk_dialog_add_button((GtkDialog *)window, "close", GTK_RESPONSE_CLOSE);
g_signal_connect_swapped(button, "response", (GCallback *)gtk_widget_destroy, window);

gtk_widget_set_can_default(button, TRUE);  
gtk_widget_grab_default(button);

gtk_widget_show(button); 
gtk_widget_show(window);

gtk_dialog_run((GtkDialog*)window);
gtk_widget_destroy(window);

Solution

  • For the top section you gtk_dialog_get_content_area. This will return a VBox, where you can pack your own widgets.

    For the bottom section you either gtk_dialog_add_button or gtk_dialog_add_action_widget.


    The GtkDialog contains only private fields and should not be directly accessed.

    If you want to add a non-activatable widget, simply pack it into the action_area field of the GtkDialog struct.

    You should obtain a pointer to action_area with deprecated (!)gtk_dialog_get_action_area, but that will not allow to register a response id.