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`. And many static variables in `tfepplication.c`. The file `tfeapplication.c` should be divided into several files. - `tfeapplication.c` only has codes related to the application. - A file for the main window - 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 can be defined as a 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. The widget is defined with template tag, not object tag. Next subsection shows how to build a preference dialog. ## Preference dialog First, write a template XML file. ~~~xml 1 2 3 32 33 ~~~ Template tag specifies a composite widget. The value of a class attribute is the object name. It is "TfePref". A parent attribute specifies the direct parent class of the composite widget. Therefore. `TfePref` is a child class of `GtkDialog`. A parent attribute is optional. But it is recommended to specify it. Other lines are the same as before. The class `TfePref` is defined like TfeTextView. There are two files `tfepref.h` and `tfepref.c`. The file `tfepref.h` defines types and declares public functions. The definitions are public and open to any C files. ~~~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 (void); 11 12 #endif /* __TFE_PREF_H__ */ 13 ~~~ - 6: Defines a type `TFE_TYPE_PREF`, which is a macro replaced by `tfe_pref_get_type ()`. - 7: The macro `G_DECLAER_FINAL_TYPE` expands to: - The function `tfe_pref_get_type ()` is declared. - TfePrep type is defined as a typedef of `struct _TfePrep`. - TfePrepClass type is defined as a typedef of `struct {GtkDialogClass *parent;}`. - Two functions `TFE_PREF ()` and `TFE_IS_PREF ()` is defined. - 9-10: `tfe_pref_new` creates a new TfePref object. The file `tfepref.c` includes: - `struct _TfePrep` structure - `G_DEFINE_TYPE` macro - Initialize and dispose functions - public functions ~~~C 1 #include 2 #include "tfepref.h" 3 4 struct _TfePref 5 { 6 GtkDialog parent; 7 GSettings *settings; 8 GtkFontButton *fontbtn; 9 }; 10 11 G_DEFINE_TYPE (TfePref, tfe_pref, GTK_TYPE_DIALOG); 12 13 static void 14 tfe_pref_dispose (GObject *gobject) { 15 TfePref *pref = TFE_PREF (gobject); 16 17 g_clear_object (&pref->settings); 18 G_OBJECT_CLASS (tfe_pref_parent_class)->dispose (gobject); 19 } 20 21 static void 22 tfe_pref_init (TfePref *pref) { 23 gtk_widget_init_template (GTK_WIDGET (pref)); 24 pref->settings = g_settings_new ("com.github.ToshioCP.tfe"); 25 g_settings_bind (pref->settings, "font", pref->fontbtn, "font", G_SETTINGS_BIND_DEFAULT); 26 } 27 28 static void 29 tfe_pref_class_init (TfePrefClass *class) { 30 GObjectClass *object_class = G_OBJECT_CLASS (class); 31 32 object_class->dispose = tfe_pref_dispose; 33 gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), "/com/github/ToshioCP/tfe/tfepref.ui"); 34 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), TfePref, fontbtn); 35 } 36 37 GtkWidget * 38 tfe_pref_new (void) { 39 return GTK_WIDGET (g_object_new (TFE_TYPE_PREF, NULL)); 40 } 41 ~~~ - 4-9: The structure `struct _TfePref` is defined. Every TfePref instance has its own data of the structure. The structure has references to: - a GSettings instance - a FontButton instance - 11: `G_DEFINE_TYPE` macro. The macro expands to: - the declaration of the class initialization function `tfe_pref_class_init` - the declaration of the instance initialization function `tfe_pref_init` - a static variable `tfe_pref_parent_class` that points the parent class (GtkDialogClass) structure. - a definition of `tfe_pref_get_type ()` function - 13-19: `tfe_pref_dispose` function. It is called in the destruction process and releases all the reference to other objects. For further information about destruction process, refer to [Section 11](sec11.md). - 17: g\_clear\_object is often used in dispose handlers. `g_clear_object (&pref->gsettings)` does: - `g_object_unref (pref->gsettings)` - `pref->settings = NULL` - 21-26: Instance initialization function. The argument `pref` points a newly created TfePref instance. - 23: The function `gtk_widget_init_template` creates and initializes the child widgets. The widgets are created based on the template which is created in the `gtk_widget_class_set_template_from_resource` function. - 24: Creates GSettings instance and assigns the pointer to it into `pref->settings`. The instance refers to a GSetting id `com.github.ToshioCP.tfe`. - 25: Binds the GSettings data `font` and the `font` property of `pref->fontbtn` (GtkFontButton). The element `pref->fontbtn` points the GtkFontButton, which is the instance of `fontbtn` in the ui file. The relation was made by the `gtk_widget_class_bind_template_child` function. - 28-35: Class initialization function. - 32: Sets the dispose handler. - 33: `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 makes the class recognize the structure of the object. That's why the top level tag is not `` but `