Modify section 9 and 10.

This commit is contained in:
Toshio Sekiya 2021-01-08 15:52:33 +09:00
parent 6878ec19ce
commit 3b70d2bdc6
7 changed files with 60 additions and 63 deletions

2
.gitignore vendored
View file

@ -10,6 +10,8 @@ src/tfv/a.out
src/tfe/a.out src/tfe/a.out
src/tfe/hello.txt src/tfe/hello.txt
src/tfe/resources.c src/tfe/resources.c
src/tfe5/_build
src/tfe5/hello.txt
# backup file # backup file
*~ *~

BIN
image/TfeTextView.ods Executable file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View file

@ -28,7 +28,7 @@ This is done usually when the class is initialized.
3. When it is emmitted, the connected handler is invoked. 3. When it is emmitted, the connected handler is invoked.
Step one and three are done in the object on which the signal is emitted. Step one and three are done in the object on which the signal is emitted.
Step two is done outside the objects. Step two is usually done outside the objects.
## Signal registration ## Signal registration
@ -58,7 +58,7 @@ Signal registration codes are written in the class initialization function.
- 6-15: Register "change-file"signal. - 6-15: Register "change-file"signal.
`g_signal_newv` function is used. `g_signal_newv` function is used.
This signal has no default handler (object method handler). This signal has no default handler (object method handler).
I think you usually don't need to set a default handler in final type object. You usually don't need to set a default handler in final type object.
If you need it, put the closure of the handler in line 9. If you need it, put the closure of the handler in line 9.
- The return value of `g_signal_newv` is the signal id. - The return value of `g_signal_newv` is the signal id.
The type of signal id is guint, which is the same as unsigned int. The type of signal id is guint, which is the same as unsigned int.
@ -95,14 +95,14 @@ The parameter is defined in `tfetextview.h` because it is public.
}; };
- `TFE_OPEN_RESPONSE_SUCCESS` is set when `tfe_text_view_open` successfully has opend a file and loaded it. - `TFE_OPEN_RESPONSE_SUCCESS` is set when `tfe_text_view_open` successfully has opend a file and loaded it.
- `TFE_OPEN_RESPONSE_CANCEL` is set when the user canceled to open a file. - `TFE_OPEN_RESPONSE_CANCEL` is set when the user has canceled to open a file.
- `TFE_OPEN_RESPONSE_ERROR` is set when error occured. - `TFE_OPEN_RESPONSE_ERROR` is set when error has occured.
## Signal connection ## Signal connection
A signal and a handler are connected by the function `g_signal_connect`. A signal and a handler are connected by the function `g_signal_connect`.
There some similar functions like `g_signal_connect_after`, `g_signal_connect_swapped` and so on. There are some similar functions like `g_signal_connect_after`, `g_signal_connect_swapped` and so on.
But I think `g_signal_connect` is the most common function. However, `g_signal_connect` is the most common function.
The signals "change-file" is connected to a callback function `file_changed` outside of TfeTextView object. The signals "change-file" is connected to a callback function `file_changed` outside of TfeTextView object.
In the same way, the signals "open-response" is connected to a callback function `open_response` outside of TfeTextView object. In the same way, the signals "open-response" is connected to a callback function `open_response` outside of TfeTextView object.
The functions `file_changed` and `open_response` will be explained later. The functions `file_changed` and `open_response` will be explained later.

View file

@ -44,10 +44,10 @@ Each function is defined as follows.
@@@ tfe5/tfetextview.c tfe_text_view_new_with_file tfe_text_view_new @@@ tfe5/tfetextview.c tfe_text_view_new_with_file tfe_text_view_new
- 18-21: `tfe_text_view_new`. - 21-24: `tfe_text_view_new`.
Just returns the value from the function `gtk_widget_new`. Just returns the value from the function `g_object_new` but casted to the pointer to GtkWidget.
Initialization is done in `tfe_text_view_init` which is called in the process of `gtk_widget_new` function. Initialization is done in `tfe_text_view_init` which is called in the process of `gtk_widget_new` function.
- 1-16: `tfe_text_view_new_with_file` - 1-19: `tfe_text_view_new_with_file`
- 3: `g_return_val_if_fail` is described in [Glib API reference](https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#g-return-val-if-fail). - 3: `g_return_val_if_fail` is described in [Glib API reference](https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#g-return-val-if-fail).
It tests whether the argument `file` is a pointer to GFile. It tests whether the argument `file` is a pointer to GFile.
If it's true, then the program goes on to the next line. If it's true, then the program goes on to the next line.
@ -57,9 +57,10 @@ This function is used to check the programmer's error.
If an error occurs, the solution is usually to change the (caller) program and fix the bug. If an error occurs, the solution is usually to change the (caller) program and fix the bug.
You need to distinguish programmer's errors and runtime errors. You need to distinguish programmer's errors and runtime errors.
You shouldn't use this function to find runtime errors. You shouldn't use this function to find runtime errors.
- 9-10: If an error occurs when reading the file, then return NULL. - 10-11: If an error occurs when reading the file, then return NULL.
- 11-15: Generate TfeTextView and set the pointer to it to `tv`. - 13-18: Generate TfeTextView and set the pointer to it to `tv`.
Set the contents read from the file to GtkTextBuffer `tv->tb`. The pointer to GtkTextBuffer is set to `tb`
Set the contents read from the file to GtkTextBuffer `tb`.
Free the memories pointed by `contents`. Free the memories pointed by `contents`.
Duplicate `file` and set it to `tv->file`. Duplicate `file` and set it to `tv->file`.
Return `tv`. Return `tv`.

View file

@ -1,6 +1,6 @@
# Instance and class # Instance and class
This section and the following four sections are descriptions about next version of the text file editor (tfe). This section and the following four sections are explanations about the next version of the text file editor (tfe).
It is tfe5. It is tfe5.
It has many changes from the prior version. It has many changes from the prior version.
All the sources are listed after the five sections. All the sources are listed after the five sections.
@ -15,8 +15,8 @@ It should be divided at least into two parts, `tfeapplication.c` and `tfenoteboo
- Header files also need to be organized. - Header files also need to be organized.
However, first of all, I'd like to focus on the object TfeTextView. However, first of all, I'd like to focus on the object TfeTextView.
It is a child object of GtkTextView. It is a child object of GtkTextView and has a new member `file` in it.
And important thing is it has newly added Gfile in it. The important thing is to manage the Gfile object pointed by `file`.
- What is necessary to GFile when generating (or initializing) TfeTextView? - What is necessary to GFile when generating (or initializing) TfeTextView?
- What is necessary to GFile when destructing TfeTextView? - What is necessary to GFile when destructing TfeTextView?
@ -34,7 +34,7 @@ After that I will explain:
GObject and its children are objects, which have both class and instance. GObject and its children are objects, which have both class and instance.
First, think about instance of objects. First, think about instance of objects.
Instance is structured memories and the structure is described using C language structure. Instance is structured memories and the structure is described as C language structure.
The following is a structure of TfeTextView. The following is a structure of TfeTextView.
/* This typedef statement is automaticaly generated by the macro G_DECLARE_FINAL_TYPE */ /* This typedef statement is automaticaly generated by the macro G_DECLARE_FINAL_TYPE */
@ -42,19 +42,14 @@ The following is a structure of TfeTextView.
struct _TfeTextView { struct _TfeTextView {
GtkTextView parent; GtkTextView parent;
GtkTextBuffer *tb;
GFile *file; GFile *file;
gboolean changed;
}; };
Each instance has similar structure as above. The members of the structure are:
- `parent` is the structure of GtkTextView which is the parent object of TfeTextView. - `parent` is the structure of GtkTextView which is the parent object of TfeTextView.
- `tb` is a pointer to GtkTextBuffer connected to GtkTextView. - `file` is a pointer to GFile. It can be NULL if no file corresponds to the TfeTextView object.
- `file` is a pointer to GFile which is a file corresponds to `tb` (or NULL is available).
- `changed` is TRUE if the buffer has been modified, FALSE if not.
Comparing to the source file in the previous section, `tb` and `changed` are added.
Notice the program above is the declaration of the structure, not the definition. Notice the program above is the declaration of the structure, not the definition.
So, no memories are allocated at this moment. So, no memories are allocated at this moment.
They are to be allocated when `tfe_text_view_new` function is invoked. They are to be allocated when `tfe_text_view_new` function is invoked.
@ -110,19 +105,19 @@ When this function is run, the following procedure is gone through.
Step one through three is done automatically. Step one through three is done automatically.
Step four is done by the function `tfe_text_view_init`. Step four is done by the function `tfe_text_view_init`.
> (In the same way, `gtk_text_view_init`, `gtk_widget_init` and `g_object_init` is the initialization functions of GtkTextView, GtkWidget and GObject respectively. > In the same way, `gtk_text_view_init`, `gtk_widget_init` and `g_object_init` is the initialization functions of GtkTextView, GtkWidget and GObject respectively.
> You can find them in the GTK or GLib source file.) > You can find them in the GTK or GLib source files.
@@@ tfe5/tfetextview.c on_changed tfe_text_view_init @@@ tfe5/tfetextview.c tfe_text_view_init
`tfe_text_view_init` initializes the instance. `tfe_text_view_init` initializes the instance.
- 8-10: Initialize `tb`, `file` and `changed`. - 3: Get the pointer to GtkTextBuffer and assign it to `tb`.
- 11: Set the wrap mode of GtkTextView as GTK\_WRAP\_WORD\_CHAR. - 5: Initialize `tv->file = NULL`.
- 12: Connect "changed" signal to a handler `on_changed`. - 6: Set modified bit to FALSE. That means the GtkTextBuffer has not modified.
"changed" signal is defined in GtkTextBuffer. When the buffer is modified, it will automatically toggled on the modified bit.
It is emitted when the contents in the buffer is changed. Whenever the buffer is saved to disk, call gtk_text_buffer_set_modified (buffer , FALSE).
- 2-4: `on_changed` handler records TRUE to `tv->changed` when "changed" signal is emitted. - 7: Set the wrap mode of GtkTextView as GTK\_WRAP\_WORD\_CHAR.
## Functions and Classes ## Functions and Classes
@ -130,16 +125,18 @@ In Gtk, all objects derived from GObject have class and instance.
Instance is memories which has a structure defined by C structure declaration as I mentioned in the previous two subsections. Instance is memories which has a structure defined by C structure declaration as I mentioned in the previous two subsections.
And instance can be generated two or more. And instance can be generated two or more.
Those instances have the same structure. Those instances have the same structure.
However, structured memories are insufficient to define its behavior. Instance, which is structured memories, only keeps status of the object.
Therefore, it is insufficient to define its behavior.
We need at least two things. We need at least two things.
One is functions and the other is class. One is functions and the other is class.
You've already seen many functions, for example, `tfe_text_view_new` is a function to generate TfeTextView instance. You've already seen many functions.
These functions are similar to object methods in object oriented languages such as Java and Ruby. For example, `tfe_text_view_new` is a function to generate TfeTextView instance.
These functions are similar to object methods in object oriented languages such as Java or Ruby.
Functions are public, which means that they are expected to be used by other objects. Functions are public, which means that they are expected to be used by other objects.
Class comprises mainly pointers to functions. Class comprises mainly pointers to functions.
And the functions are used by the object itself or its children objects. Those functions are used by the object itself or its descendent objects.
For example, GObject class is declared in `gobject.h` in GLib source files. For example, GObject class is declared in `gobject.h` in GLib source files.
@@@ class_gobject.c @@@ class_gobject.c
@ -159,9 +156,9 @@ In the same way, line 23 says `finalize` is a pointer to the function which has
Look at the declaration of `_GObjectClass` so that you would find that most of the members are pointers to functions. Look at the declaration of `_GObjectClass` so that you would find that most of the members are pointers to functions.
- 10: A function pointed by `constructor` is called when the instance is generated. It completes the initialization of the instance. - 10: A function pointed by `constructor` is called when the instance is generated. It completes the initialization of the instance.
- 22: A function pointed by `dispose` is called when the instance destructs itself. Destruction process is divided into two phases. First is called disposing and the instance releases all the references to other instances. The second is finalizing. - 22: A function pointed by `dispose` is called when the instance destructs itself. Destruction process is divided into two phases. The first one is called disposing and the instance releases all the references to other instances. The second one is finalizing.
- 23: A funtion pointed by `finalize` finishes the destruction process. - 23: A funtion pointed by `finalize` finishes the destruction process.
- The other pointers point functions which are called during the instance lives. - The other pointers point functions which are called while the instance lives.
## TfeTextView class ## TfeTextView class
@ -178,11 +175,11 @@ The following is extracts from the source files (not exactly the same).
So, they are not written in either `tfe_text_view.h` or `tfe_text_view.c`. So, they are not written in either `tfe_text_view.h` or `tfe_text_view.c`.
- 2, 73, 106: Each derived class puts its parent class at the first member of its structure. - 2, 73, 106: Each derived class puts its parent class at the first member of its structure.
It is the same as instance structures. It is the same as instance structures.
- Class members in ancesters are open to their child class. - Class members in ancesters are open to the descendent class.
So, they can be changed in `tfe_text_view_class_init` function. So, they can be changed in `tfe_text_view_class_init` function.
For example, the `dispose` pointer in GObjectClass will be overridden later in `tfe_text_view_class_init`. For example, the `dispose` pointer in GObjectClass will be overridden later in `tfe_text_view_class_init`.
(Override is an object oriented programing terminology. (Override is an object oriented programing terminology.
Override is rewriting ancestors' class methods in the child class.) Override is rewriting ancestors' class methods in the descendent class.)
- Some class methods are often overridden. - Some class methods are often overridden.
`set_property`, `get_property`, `dispose`, `finalize` and `constructed` are such methods. `set_property`, `get_property`, `dispose`, `finalize` and `constructed` are such methods.
@ -235,7 +232,7 @@ The function `tfe_text_view_class_init` is the class initialization function and
} }
Each ancestors' class is generated before TfeTextViewClass. Each ancestors' class has been generated before TfeTextViewClass is generated.
Therefore, there are four classes and each class has a pointer to each dispose handler. Therefore, there are four classes and each class has a pointer to each dispose handler.
Look at the following diagram. Look at the following diagram.
There are four classes -- GObjectClass (GInitiallyUnownedClass), GtkWidgetClass, GtkTextViewClass and TfeTextViewClass. There are four classes -- GObjectClass (GInitiallyUnownedClass), GtkWidgetClass, GtkTextViewClass and TfeTextViewClass.
@ -251,7 +248,7 @@ Then it invokes its parent's dispose handler in line 8.
`tfe_text_view_parent_class`,which is made by `G_DEFINE_TYPE` macro, is a pointer that points the parent object class. `tfe_text_view_parent_class`,which is made by `G_DEFINE_TYPE` macro, is a pointer that points the parent object class.
Therefore, `G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose` points the handler `dh3` in the diagram above. Therefore, `G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose` points the handler `dh3` in the diagram above.
And `gobject` is a pointer to TfeTextView object which is casted as a GObject instanse. And `gobject` is a pointer to TfeTextView instance which is casted as a GObject instanse.
`dh3` releases all the references to objects in the GtkTextView part (it is actually the private area pointed by `prev`) in TfeTextView instance. `dh3` releases all the references to objects in the GtkTextView part (it is actually the private area pointed by `prev`) in TfeTextView instance.
After that, `dh3` calls `dh2`, and `dh2` calls `dh1`. After that, `dh3` calls `dh2`, and `dh2` calls `dh1`.
Finally all the references are released. Finally all the references are released.

View file

@ -3,9 +3,7 @@
struct _TfeTextView struct _TfeTextView
{ {
GtkTextView parent; GtkTextView parent;
GtkTextBuffer *tb;
GFile *file; GFile *file;
gboolean changed;
}; };
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW); G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
@ -18,12 +16,6 @@ enum {
static guint tfe_text_view_signals[NUMBER_OF_SIGNALS]; static guint tfe_text_view_signals[NUMBER_OF_SIGNALS];
/* Signal handler */
static void
on_changed (GtkTextBuffer *tb, TfeTextView *tv) {
tv->changed=TRUE;
}
static void static void
tfe_text_view_dispose (GObject *gobject) { tfe_text_view_dispose (GObject *gobject) {
TfeTextView *tv = TFE_TEXT_VIEW (gobject); TfeTextView *tv = TFE_TEXT_VIEW (gobject);
@ -36,11 +28,11 @@ tfe_text_view_dispose (GObject *gobject) {
static void static void
tfe_text_view_init (TfeTextView *tv) { tfe_text_view_init (TfeTextView *tv) {
tv->tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
tv->file = NULL; tv->file = NULL;
tv->changed = FALSE; gtk_text_buffer_set_modified (tb, FALSE);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
g_signal_connect (tv->tb, "changed", G_CALLBACK (on_changed), tv);
} }
static void static void
@ -80,6 +72,7 @@ tfe_text_view_get_file (TfeTextView *tv) {
static void static void
open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) { open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
GFile *file; GFile *file;
char *contents; char *contents;
gsize length; gsize length;
@ -101,10 +94,10 @@ open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
g_error_free (err); g_error_free (err);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR); g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
} else { } else {
gtk_text_buffer_set_text (tv->tb, contents, length); gtk_text_buffer_set_text (tb, contents, length);
g_free (contents); g_free (contents);
tv->file = file; tv->file = file;
/* tv->changed = FALSE;*/ /* gtk_text_buffer_set_modified (tb, FALSE);*/
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS); g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
} }
gtk_window_destroy (GTK_WINDOW (dialog)); gtk_window_destroy (GTK_WINDOW (dialog));
@ -126,13 +119,14 @@ tfe_text_view_open (TfeTextView *tv) {
static void static void
saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) { saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
GFile *file; GFile *file;
if (response == GTK_RESPONSE_ACCEPT) { if (response == GTK_RESPONSE_ACCEPT) {
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
if (G_IS_FILE(file)) { if (G_IS_FILE(file)) {
tv->file = file; tv->file = file;
tv->changed = TRUE; gtk_text_buffer_set_modified (tb, TRUE);
g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0); g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
tfe_text_view_save (TFE_TEXT_VIEW (tv)); tfe_text_view_save (TFE_TEXT_VIEW (tv));
} }
@ -144,6 +138,7 @@ void
tfe_text_view_save (TfeTextView *tv) { tfe_text_view_save (TfeTextView *tv) {
g_return_if_fail (TFE_IS_TEXT_VIEW (tv)); g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
GtkTextIter start_iter; GtkTextIter start_iter;
GtkTextIter end_iter; GtkTextIter end_iter;
gchar *contents; gchar *contents;
@ -151,15 +146,15 @@ tfe_text_view_save (TfeTextView *tv) {
GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW); GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
GError *err = NULL; GError *err = NULL;
if (! tv->changed) if (! gtk_text_buffer_get_modified (tb))
return; /* no necessary to save it */ return; /* no necessary to save it */
else if (tv->file == NULL) else if (tv->file == NULL)
tfe_text_view_saveas (tv); tfe_text_view_saveas (tv);
else { else {
gtk_text_buffer_get_bounds (tv->tb, &start_iter, &end_iter); gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
contents = gtk_text_buffer_get_text (tv->tb, &start_iter, &end_iter, FALSE); contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err)) if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err))
tv->changed = FALSE; gtk_text_buffer_set_modified (tb, FALSE);
else { else {
/* It is possible that tv->file is broken. */ /* It is possible that tv->file is broken. */
/* It is a good idea to set tv->file to NULL. */ /* It is a good idea to set tv->file to NULL. */
@ -167,7 +162,7 @@ tfe_text_view_save (TfeTextView *tv) {
g_object_unref (tv->file); g_object_unref (tv->file);
tv->file =NULL; tv->file =NULL;
g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0); g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
tv->changed = TRUE; gtk_text_buffer_set_modified (tb, TRUE);
message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL, message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
"%s.\n", err->message); "%s.\n", err->message);
@ -198,6 +193,7 @@ tfe_text_view_new_with_file (GFile *file) {
g_return_val_if_fail (G_IS_FILE (file), NULL); g_return_val_if_fail (G_IS_FILE (file), NULL);
GtkWidget *tv; GtkWidget *tv;
GtkTextBuffer *tb;
char *contents; char *contents;
gsize length; gsize length;
@ -205,7 +201,8 @@ tfe_text_view_new_with_file (GFile *file) {
return NULL; return NULL;
tv = tfe_text_view_new(); tv = tfe_text_view_new();
gtk_text_buffer_set_text (TFE_TEXT_VIEW (tv)->tb, contents, length); tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
gtk_text_buffer_set_text (tb, contents, length);
g_free (contents); g_free (contents);
TFE_TEXT_VIEW (tv)->file = g_file_dup (file); TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
return tv; return tv;
@ -213,6 +210,6 @@ tfe_text_view_new_with_file (GFile *file) {
GtkWidget * GtkWidget *
tfe_text_view_new (void) { tfe_text_view_new (void) {
return gtk_widget_new (TFE_TYPE_TEXT_VIEW, NULL); return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
} }