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.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:
Next subsection shows how to build a preference dialog.
First, write a template XML file.
@@@include tfe7/tfepref.ui @@@
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.
@@@include tfe7/tfepref.h @@@
TFE_TYPE_PREF
, which is a macro
replaced by tfe_pref_get_type ()
.G_DECLAER_FINAL_TYPE
expands to:
tfe_pref_get_type ()
is declared.struct _TfePrep
.struct {GtkDialogClass *parent;}
.TFE_PREF ()
and
TFE_IS_PREF ()
is defined.tfe_pref_new
creates a new TfePref object.The file tfepref.c
includes:
struct _TfePrep
structureG_DEFINE_TYPE
macro@@@include tfe7/tfepref.c @@@
struct _TfePref
is defined. Every
TfePref instance has its own data of the structure. The structure has
references to:
G_DEFINE_TYPE
macro. The macro expands to:
tfe_pref_class_init
tfe_pref_init
tfe_pref_parent_class
that points the
parent class (GtkDialogClass) structure.tfe_pref_get_type ()
functiontfe_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.g_clear_object (&pref->gsettings)
does:
g_object_unref (pref->gsettings)
pref->settings = NULL
pref
points a newly created TfePref instance.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.pref->settings
. The instance refers to a GSetting id
com.github.ToshioCP.tfe
.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.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 <object>
but
<template>
in the XML file. The instance will be
created in the gtk_widget_init_template
function
later.gtk_widget_class_bind_template_child
macro binds
the structure member (fontbtn
in
struct _TfePref
) and the id fontbtn
in the XML
file. The two names must be the same. This binding is between the member
and the template (not an instance).tfe_pref_new
creates a TfePref
instance.Now, It is very simple to use this dialog. A caller just creates this object and shows it.
*pref;
TfePref = tfe_pref_new ();
pref (GTK_WINDOW (pref), win); /* win is the main window */
gtk_window_set_transient_for (GTK_WINDOW (pref)); gtk_window_present
This instance is automatically destroyed when a user clicks on the close button. That’s all. If you want to show the dialog again, just create and show it.
It is almost same as preference dialog.
Its ui file is:
@@@include tfe7/tfealert.ui @@@
The header file is:
@@@include tfe7/tfealert.h @@@
There are three public functions. The functions
tfe_alert_set_message
and
tfe_alert_set_button_label
sets the label and button name
of the alert dialog. For example, if you want to show an alert that the
user tries to close without saving the content, set them like:
(alert, "Contents aren't saved yet.\nAre you sure to close?");
tfe_alert_set_message (alert, "Close"); tfe_alert_set_button_label
The function tfe_alert_new
creates a TfeAlert
dialog.
The C source file is:
@@@include tfe7/tfealert.c @@@
The program is almost same as tfepref.c
.
The Usage of the alert object is as follows.
TfeWindow
is a child class of GtkApplicationWindow.
@@@include tfe7/tfewindow.ui @@@
This XML file is almost same as before except template tag and “action-name” property in buttons.
GtkButton implements GtkActionable interface, which has “action-name”
property. If this property is set, GtkButton activates the action when
it is clicked. For example, if an open button is clicked, “win.open”
action will be activated and open_activated
handler will be
invoked.
This action is also used by “<Control>o” accelerator (See
tfeapplication.c
). If you used “clicked” signal for the
button, you would need its signal handler. Then, there would be two
handlers:
These two handlers are almost same. It is inefficient. Connecting buttons to actions is a good way to reduce unnecessary codes.
@@@include tfe7/tfewindow.h @@@
There are three public functions. The function
tfe_window_notebook_page_new
creates a new notebook page.
This is a wrapper function for notebook_page_new
. It is
called by TfeApplication object. The function
tfe_window_notebook_page_new_with_files
creates notebook
pages with a contents read from the given files. The function
tfe_window_new
creates a TfeWindow instance.
@@@include tfe7/tfewindow.c @@@
_TfeWindow
structure. A TfeWindow instance points
the structure.G_DEFINE_TYPE
macro.alert_response_cb
is a call back function for
the “response” signal of TfeAlert dialog.has_saved_all
returns true, the handler returns
false and the window will close. Otherwise, it shows an alert
dialog.user_data
is a pointer to the TfeWindow instance.gtk_widget_init_template
creates a
child widgets and initializes them.menu
. It is inserted to the
menu button.tfe_window_new
. This function creates
TfeWindow instance.The file tfeaplication.h
and
tfeapplication.c
are now very simple. The following is the
header file.
@@@include tfe7/tfeapplication.h @@@
#pragma once
isn’t an official pre-processor
command, but widely used. It makes the header file be read only
once.TFE_TYPE_APPLICATION
is defined as the type of
TfeApplication. G_DECLARE_FINAL_TYPE
is a macro used in the
header file to define a new object.tfe_application_new
creates a new
TfeApplication instance.The following is tfeapplication.c
. It defines the
application and supports:
@@@include tfe7/tfeapplication.c @@@
_TfeApplication
structure. The members
are:
G_DEFINE_TYPE
macro.changed_font_cb
is a handler for “changed::font”
signal on the GSettings instance. The signal name is “changed” and
“font” is a key name. When the valeu of “font” key is changed, the
signal is emitted. So, this handler doesn’t directly relate to the font
button, but through the GSettings database. A user changes the font in
the font button => GSettings font key data is changed => the
handler is called.tfe_window_notebook_page_new
instead of
notebook_page_new
.tfe_window_notebook_page_new_with_files
and shows the main
window. Be careful that the activate and open handlers don’t create a
new window. They just create a new notebook page. Therefore, even if the
second application runs, no new window appears. Just a new notebook page
is inserted to the same main window.app->win
.provider0
). It includes
only the padding data for the textview. The provider is inserted to the
default display.app->provider
) and inserted to the default display. It
will include the font data for the textview.changed_font_cb
is called to set the CSS with
the font data. The handler gets the font data from the GSettings data
which is the last font in the previous run of the application.tfe_application_new
creates a new
TfeApplication instance. The parameters are an application-id and
flags.main.c
@@@include tfe7/main.c @@@
CSS related files pfd2css.h
and pfd2css.c
are the same as the previous section.
Resource XML file.
@@@include tfe7/tfe.gresource.xml @@@
GSchema XML file
@@@include tfe7/com.github.ToshioCP.tfe.gschema.xml @@@
Meson.build
@@@include tfe7/meson.build @@@
If you want to install it to your local area, use
--prefix=$HOME/.local
or --prefix=$HOME
option. If you want to install it to the system area, no option is
needed. It will be installed under /user/local
directory.
$ meson --prefix=$HOME/.local _build
$ ninja -C _build
$ ninja -C _build install
You need root privilege to install it to the system area..
$ meson _build
$ ninja -C _build
$ sudo ninja -C _build install
Source files are in src/tfe7 directory.
Composite widgets give us two advantages.
We made a very small text editor. You can add features to this editor. When you add a new feature, be careful about the structure of the program. Maybe you need to divide a file into several files like this section. It isn’t good to put many things into one file. And it is important to think about the relationship between source files and widget structures.