Up: [Readme.md](../Readme.md), Prev: [Section 20](sec20.md), Next: [Section 22](sec22.md) # Template XML and composite widget The tfe program in the previous section is not so good because many things are crammed into `tfepplication.c`. Many static variables in `tfepplication.c` shows that. ~~~C static GtkDialog *pref; static GtkFontButton *fontbtn; static GSettings *settings; static GtkDialog *alert; static GtkLabel *lb_alert; static GtkButton *btn_accept; static gulong pref_close_request_handler_id = 0; static gulong alert_close_request_handler_id = 0; static gboolean is_quit; ~~~ Generally, if there are many global or static variables in the program, it is not a good program. Such programs are difficult to maintain. The file `tfeapplication.c` should be divided into several files. - `tfeapplication.c` only has codes related to GtkApplication. - A file for GtkApplicationWindow - A file for a preference dialog - A file for an alert dialog The preference dialog is defined by a ui file. And it has GtkBox, GtkLabel and GtkFontButton in it. Such widget is called composite widget. Composite widget is a child object (not child widget) of a widget. For example, the preference composite widget is a child object of GtkDialog. Composite widget can be built from template XML. Next subsection shows how to build a preference dialog. ## Preference dialog First, write a template XML file. ~~~xml 1 2 3 32 33 ~~~ - 3: Template tag specifies a composite widget. The value of a class attribute is the object name of the composite widget. This XML file names the object "TfePref". It is defined in a C source file and it will be shown later. A parent attribute specifies the direct parent object of the composite widget. `TfePref` is a child object of `GtkDialog`. Therefore the value of the attribute is "GtkDialog". A parent attribute is optional but it is recommended to specify. Other lines are the same as before. The object `TfePref` is defined in `tfepref.h` and `tfepref.c`. ~~~C 1 #ifndef __TFE_PREF_H__ 2 #define __TFE_PREF_H__ 3 4 #include 5 6 #define TFE_TYPE_PREF tfe_pref_get_type () 7 G_DECLARE_FINAL_TYPE (TfePref, tfe_pref, TFE, PREF, GtkDialog) 8 9 GtkWidget * 10 tfe_pref_new (GtkWindow *win); 11 12 #endif /* __TFE_PREF_H__ */ 13 ~~~ - 6-7: When you define a new object, you need to write these two lines. Refer to [Section 8](sec8.md). - 9-10: `tfe_pref_new` creates a new TfePref object. It has a parameter `win` which is used as a transient parent window to show the dialog. ~~~C 1 #include "tfepref.h" 2 3 struct _TfePref 4 { 5 GtkDialog parent; 6 GSettings *settings; 7 GtkFontButton *fontbtn; 8 }; 9 10 G_DEFINE_TYPE (TfePref, tfe_pref, GTK_TYPE_DIALOG); 11 12 static void 13 tfe_pref_dispose (GObject *gobject) { 14 TfePref *pref = TFE_PREF (gobject); 15 16 g_clear_object (&pref->settings); 17 G_OBJECT_CLASS (tfe_pref_parent_class)->dispose (gobject); 18 } 19 20 static void 21 tfe_pref_init (TfePref *pref) { 22 gtk_widget_init_template (GTK_WIDGET (pref)); 23 pref->settings = g_settings_new ("com.github.ToshioCP.tfe"); 24 g_settings_bind (pref->settings, "font", pref->fontbtn, "font", G_SETTINGS_BIND_DEFAULT); 25 } 26 27 static void 28 tfe_pref_class_init (TfePrefClass *class) { 29 GObjectClass *object_class = G_OBJECT_CLASS (class); 30 31 object_class->dispose = tfe_pref_dispose; 32 gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), "/com/github/ToshioCP/tfe/tfepref.ui"); 33 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), TfePref, fontbtn); 34 } 35 36 GtkWidget * 37 tfe_pref_new (GtkWindow *win) { 38 return GTK_WIDGET (g_object_new (TFE_TYPE_PREF, "transient-for", win, NULL)); 39 } 40 ~~~ - 3-8: The structure of an instance of this object. It has two variables, settings and fontbtn. - 10: `G_DEFINE_TYPE` macro. This macro registers the TfePref type. - 12-18: Dispose handler. This handler is called when the instance is destroyed. The destruction process has two stages, disposing and finalizing. When disposing, the instance releases all the references (to the other instances). TfePref object holds a reference to the GSettings instance. It is released in line 16. After that parents dispose handler is called in line 17. For further information about destruction process, refer to [Section 11](sec11.md). - 27-34: Class initialization function. - 31: Set the dispose handler. - 32: `gtk_widget_class_set_template_from_resource` function associates the description in the XML file (`tfepref.ui`) with the widget. At this moment no instance is created. It just make the class to know the structure of the object. That's why the top level tag is not `` but `