Defining a final class

A very simple editor

We made a very simple file viewer in the previous section. Now we go on to rewrite it and turn it into very simple editor. Its source file is tfe1.c (text file editor 1) under tfe directory.

GtkTextView is a multi-line editor. So, we don’t need to write the editor from scratch. We just add two things to the file viewer:

There are a couple of ways to store the pointers.

Using global variables is easy to implement. Define a sufficient size pointer array to GFile. For example,

GFile *f[20];

The variable f[i] corresponds to the file associated with the i-th GtkNotebookPage.

However, There are two problems. The first is the size of the array. If a user gives too many arguments (more than 20 in the example above), it is impossible to store all the pointers to the GFile instances. The second is difficulty to maintain the program. We have a small program so far. But, the more you develop the program, the bigger its size grows. Generally speaking, it is very difficult to maintain global variables in a big program. When you check the global variable, you need to check all the codes that use the variable.

Making a child class is a good idea in terms of maintenance. And we prefer it rather than a global variable.

Be careful that we are thinking about “child class”, not “child widget”. Child class and child widget are totally different. Class is a term of GObject system. If you are not familiar with GObject, see:

A child class inherits everything from the parent and, in addition, extends its performance. We will define TfeTextView as a child class of GtkTextView. It has everything that GtkTextView has and adds a pointer to a GFile.

Child object of GtkTextView

How to define a child class of GtkTextView

You need to know GObject system convention. First, look at the program below.

#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)

struct _TfeTextView
{
  GtkTextView parent;
  GFile *file;
};

G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);

static void
tfe_text_view_init (TfeTextView *tv) {
}

static void
tfe_text_view_class_init (TfeTextViewClass *class) {
}

void
tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
  tv -> file = f;
}

GFile *
tfe_text_view_get_file (TfeTextView *tv) {
  return tv -> file;
}

GtkWidget *
tfe_text_view_new (void) {
  return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
}

This program shows the outline how to define a child class.

Close-request signal

Imagine that you are using this editor. First, you run the editor with arguments. The arguments are filenames. The editor reads the files and shows the window with the text of files in it. Then you edit the text. After you finish editing, you exit the editor. The editor updates files just before the window closes.

GtkWindow emits the “close-request” signal before it closes. We will connect the signal and the handler before_close. (A handler is a C function which is connected to a signal.) The function before_close is called when the signal “close-request” is emitted.

g_signal_connect (win, "close-request", G_CALLBACK (before_close), NULL);

The argument win is a GtkApplicationWindow, in which the signal “close-request” is defined, and before_close is the handler. G_CALLBACK cast is necessary for the handler. The program of before_close is as follows.

@@@include tfe/tfe1.c before_close @@@

The numbers on the left of items are line numbers in the source code.

Source code of tfe1.c

The following is the whole source code of tfe1.c.

@@@include tfe/tfe1.c @@@

Now it’s time to compile and run.

$ cd src/tfe
$ comp tfe1
$ ./a.out taketori.txt`.

Modify the contents and close the window. Make sure that the file is modified.

Now we got a very simple editor. It’s not smart. We need more features like open, save, saveas, change font and so on. We will add them in the next section and after.