mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
Bug in tfetextview.c fixed. Section 22 and some other sections are updated.
This commit is contained in:
parent
e8b34260c5
commit
a896bbd52f
13 changed files with 352 additions and 313 deletions
12
gfm/sec10.md
12
gfm/sec10.md
|
@ -21,7 +21,7 @@ However, first of all, I'd like to focus on the object TfeTextView.
|
||||||
It is a child object of GtkTextView and has a new member `file` in it.
|
It is a child object of GtkTextView and has a new member `file` in it.
|
||||||
The important thing is to manage the Gfile object pointed by `file`.
|
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 creating (or initializing) TfeTextView?
|
||||||
- What is necessary to GFile when destructing TfeTextView?
|
- What is necessary to GFile when destructing TfeTextView?
|
||||||
- TfeTextView should read/write a file by itself or not?
|
- TfeTextView should read/write a file by itself or not?
|
||||||
- How it communicates with objects outside?
|
- How it communicates with objects outside?
|
||||||
|
@ -90,7 +90,7 @@ struct _GtkTextView
|
||||||
In each structure, its parent instance is declared at the top of members.
|
In each structure, its parent instance is declared at the top of members.
|
||||||
So, every ancestors is included in the child instance.
|
So, every ancestors is included in the child instance.
|
||||||
This is very important.
|
This is very important.
|
||||||
It guarantees a child widget to derive all the features from ancestors.
|
It guarantees a child widget to inherit all the features from ancestors.
|
||||||
The structure of `TfeTextView` is like the following diagram.
|
The structure of `TfeTextView` is like the following diagram.
|
||||||
|
|
||||||
![The structure of the instance TfeTextView](../image/TfeTextView.png)
|
![The structure of the instance TfeTextView](../image/TfeTextView.png)
|
||||||
|
@ -109,7 +109,7 @@ The function `tfe_text_view_new` generates a new TfeTextView instance.
|
||||||
|
|
||||||
When this function is run, the following procedure is gone through.
|
When this function is run, the following procedure is gone through.
|
||||||
|
|
||||||
1. Initialize GObject part in TfeTextView instance.
|
1. Initialize GObject (GInitiallyUnowned) part in TfeTextView instance.
|
||||||
2. Initialize GtkWidget part in TfeTextView instance.
|
2. Initialize GtkWidget part in TfeTextView instance.
|
||||||
3. Initialize GtkTextView part in TfeTextView instance.
|
3. Initialize GtkTextView part in TfeTextView instance.
|
||||||
4. Initialize TfeTextView part in TfeTextView instance.
|
4. Initialize TfeTextView part in TfeTextView instance.
|
||||||
|
@ -131,7 +131,7 @@ This function just initializes `tv->file` to be `NULL`.
|
||||||
|
|
||||||
## Functions and Classes
|
## Functions and Classes
|
||||||
|
|
||||||
In Gtk, all objects derived from GObject have class and instance.
|
In Gtk, all objects derived from GObject have class and instance (except abstract object).
|
||||||
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.
|
||||||
Each object can have more than one instance.
|
Each object can have more than one instance.
|
||||||
Those instances have the same structure.
|
Those instances have the same structure.
|
||||||
|
@ -357,14 +357,14 @@ It is illustrated in the following diagram.
|
||||||
## Destruction of TfeTextView
|
## Destruction of TfeTextView
|
||||||
|
|
||||||
Every Object derived from GObject has a reference count.
|
Every Object derived from GObject has a reference count.
|
||||||
If an object A refers an object B, then A keeps a pointer to B in A and at the same time increases the reference count of B by one with the function `g_object_ref (B)`.
|
If an object A refers to an object B, then A keeps a pointer to B in A and at the same time increases the reference count of B by one with the function `g_object_ref (B)`.
|
||||||
If A doesn't need B any longer, then A discards the pointer to B (usually it is done by assigning NULL to the pointer) and decreases the reference count of B by one with the function `g_object_unref (B)`.
|
If A doesn't need B any longer, then A discards the pointer to B (usually it is done by assigning NULL to the pointer) and decreases the reference count of B by one with the function `g_object_unref (B)`.
|
||||||
|
|
||||||
If two objects A and B refer to C, then the reference count of C is two.
|
If two objects A and B refer to C, then the reference count of C is two.
|
||||||
If A no longer needs C, A discards the pointer to C and decreases the reference count in C by one.
|
If A no longer needs C, A discards the pointer to C and decreases the reference count in C by one.
|
||||||
Now the reference count of C is one.
|
Now the reference count of C is one.
|
||||||
In the same way, if B no longer needs C, B discards the pointer to C and decreases the reference count in C by one.
|
In the same way, if B no longer needs C, B discards the pointer to C and decreases the reference count in C by one.
|
||||||
At this moment, no object refers C and the reference count of C is zero.
|
At this moment, no object refers to C and the reference count of C is zero.
|
||||||
This means C is no longer useful.
|
This means C is no longer useful.
|
||||||
Then C destructs itself and finally the memories allocated to C is freed.
|
Then C destructs itself and finally the memories allocated to C is freed.
|
||||||
|
|
||||||
|
|
246
gfm/sec12.md
246
gfm/sec12.md
|
@ -39,7 +39,7 @@ C source files `tfeapplication.c` and `tfenotebook.c` include `tfe.h` at the beg
|
||||||
18 tfe_text_view_get_file (TfeTextView *tv);
|
18 tfe_text_view_get_file (TfeTextView *tv);
|
||||||
19
|
19
|
||||||
20 void
|
20 void
|
||||||
21 tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
21 tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
|
||||||
22
|
22
|
||||||
23 void
|
23 void
|
||||||
24 tfe_text_view_save (TfeTextView *tv);
|
24 tfe_text_view_save (TfeTextView *tv);
|
||||||
|
@ -59,26 +59,26 @@ C source files `tfeapplication.c` and `tfenotebook.c` include `tfe.h` at the beg
|
||||||
- 1,2,35: Thanks to these three lines, the following lines are included only once.
|
- 1,2,35: Thanks to these three lines, the following lines are included only once.
|
||||||
- 4: Includes gtk4 header files.
|
- 4: Includes gtk4 header files.
|
||||||
The header file `gtk4` also has the same mechanism to avoid including it multiple times.
|
The header file `gtk4` also has the same mechanism to avoid including it multiple times.
|
||||||
- 6-7: These two lines define TfeTextView.
|
- 6-7: These two lines define TfeTextView type, its class structure and some useful macros.
|
||||||
- 9-15: A definition of the value of the parameter of "open-response" signal.
|
- 9-15: A definition of the value of the parameter of "open-response" signal.
|
||||||
- 17-33: Declaration of public functions on GtkTextView.
|
- 17-33: Declarations of public functions on TfeTextView.
|
||||||
|
|
||||||
## Functions to generate TfeTextView object
|
## Functions to create TfeTextView object
|
||||||
|
|
||||||
TfeTextView Object is generated by `tfe_text_view_new` or `tfe_text_view_new_with_file`.
|
TfeTextView Object is created with `tfe_text_view_new` or `tfe_text_view_new_with_file`.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
GtkWidget *tfe_text_view_new (void);
|
GtkWidget *tfe_text_view_new (void);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
`tfe_text_view_new` just generates a new TfeTextView object and returns the pointer to the new object.
|
`tfe_text_view_new` just creates a new TfeTextView object and returns the pointer to the new object.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
GtkWidget *tfe_text_view_new_with_file (GFile *file);
|
GtkWidget *tfe_text_view_new_with_file (GFile *file);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
`tfe_text_view_new_with_file` is given a Gfile object as the argument and it loads the file into the GtkTextBuffer object, then returns the pointer to the new object.
|
`tfe_text_view_new_with_file` is given a Gfile object as the argument and it loads the file into the GtkTextBuffer object, then returns the pointer to the new object.
|
||||||
If an error occurs during the generation process, NULL is returned.
|
If an error occurs during the creation process, NULL is returned.
|
||||||
|
|
||||||
Each function is defined as follows.
|
Each function is defined as follows.
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ 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.
|
||||||
- 10-11: If an error occurs when reading the file, then return NULL.
|
- 10-11: If an error occurs when reading the file, then return NULL.
|
||||||
- 13: Calls the function `tfe_text_view_new`.
|
- 13: Calls the function `tfe_text_view_new`.
|
||||||
The function generates TfeTextView instance and returns the pointer to the instance.
|
The function creates TfeTextView instance and returns the pointer to the instance.
|
||||||
- 14: Gets the pointer to GtkTextBuffer corresponds to `tv`.
|
- 14: Gets the pointer to GtkTextBuffer corresponds to `tv`.
|
||||||
The pointer is assigned to `tb`
|
The pointer is assigned to `tb`
|
||||||
- 15: Assigns the contents read from the file to GtkTextBuffer pointed by `tb`.
|
- 15: Assigns the contents read from the file to GtkTextBuffer pointed by `tb`.
|
||||||
|
@ -142,7 +142,7 @@ void tfe_text_view_save (TfeTextView *tv)
|
||||||
|
|
||||||
The function `save` writes the contents in GtkTextBuffer to a file specified by `tv->file`.
|
The function `save` writes the contents in GtkTextBuffer to a file specified by `tv->file`.
|
||||||
If `tv->file` is NULL, then it shows GtkFileChooserDialog and prompts the user to choose a file to save.
|
If `tv->file` is NULL, then it shows GtkFileChooserDialog and prompts the user to choose a file to save.
|
||||||
Then it saves the contents to the file and sets `tv->file` to point the GFile instance of the file.
|
Then it saves the contents to the file and sets `tv->file` to point the GFile of the file.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
void tfe_text_view_saveas (TfeTextView *tv)
|
void tfe_text_view_saveas (TfeTextView *tv)
|
||||||
|
@ -154,97 +154,131 @@ If an error occurs, it is shown to the user through the message dialog.
|
||||||
The error is managed only in the TfeTextView instance and no information is notified to the caller.
|
The error is managed only in the TfeTextView instance and no information is notified to the caller.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
1 static void
|
1 static gboolean
|
||||||
2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
2 save_file (GFile *file, GtkTextBuffer *tb, GtkWindow *win) {
|
||||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
3 GtkTextIter start_iter;
|
||||||
4 GFile *file;
|
4 GtkTextIter end_iter;
|
||||||
5 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
5 gchar *contents;
|
||||||
6
|
6 GtkWidget *message_dialog;
|
||||||
7 if (response == GTK_RESPONSE_ACCEPT) {
|
7 GError *err = NULL;
|
||||||
8 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
8
|
||||||
9 if (! G_IS_FILE (file))
|
9 /* This function doesn't check G_IS_FILE (file). The caller should check it. */
|
||||||
10 g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
10 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||||
11 else {
|
11 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||||
12 save_file(file, tb, GTK_WINDOW (win));
|
12 if (g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err)) {
|
||||||
13 if (G_IS_FILE (tv->file))
|
13 gtk_text_buffer_set_modified (tb, FALSE);
|
||||||
14 g_object_unref (tv->file);
|
14 return TRUE;
|
||||||
15 tv->file = file;
|
15 } else {
|
||||||
16 gtk_text_buffer_set_modified (tb, FALSE);
|
16 message_dialog = gtk_message_dialog_new (win, GTK_DIALOG_MODAL,
|
||||||
17 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
17 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||||
18 }
|
18 "%s.\n", err->message);
|
||||||
19 }
|
19 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||||
20 gtk_window_destroy (GTK_WINDOW (dialog));
|
20 gtk_widget_show (message_dialog);
|
||||||
21 }
|
21 g_error_free (err);
|
||||||
22
|
22 return FALSE;
|
||||||
23 void
|
23 }
|
||||||
24 tfe_text_view_save (TfeTextView *tv) {
|
24 }
|
||||||
25 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
25
|
||||||
26
|
26 static void
|
||||||
27 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
27 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||||
28 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
28 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
29
|
29 GFile *file;
|
||||||
30 if (! gtk_text_buffer_get_modified (tb))
|
30 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||||
31 return; /* no need to save it */
|
31
|
||||||
32 else if (tv->file == NULL)
|
32 if (response == GTK_RESPONSE_ACCEPT) {
|
||||||
33 tfe_text_view_saveas (tv);
|
33 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||||
34 else if (! G_IS_FILE (tv->file))
|
34 if (! G_IS_FILE (file))
|
||||||
35 g_error ("TfeTextView: The pointer in this object isn't NULL nor GFile object.\n");
|
35 g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
||||||
36 else {
|
36 else if (save_file(file, tb, GTK_WINDOW (win))) {
|
||||||
37 if (save_file (tv->file, tb, GTK_WINDOW (win)))
|
37 if (G_IS_FILE (tv->file))
|
||||||
38 gtk_text_buffer_set_modified (tb, FALSE);
|
38 g_object_unref (tv->file);
|
||||||
39 }
|
39 tv->file = file;
|
||||||
40 }
|
40 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||||
41
|
41 }
|
||||||
42 void
|
42 }
|
||||||
43 tfe_text_view_saveas (TfeTextView *tv) {
|
43 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||||
44 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
44 }
|
||||||
45
|
45
|
||||||
46 GtkWidget *dialog;
|
46 void
|
||||||
47 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
47 tfe_text_view_save (TfeTextView *tv) {
|
||||||
48
|
48 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
49 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
49
|
||||||
50 "Cancel", GTK_RESPONSE_CANCEL,
|
50 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
51 "Save", GTK_RESPONSE_ACCEPT,
|
51 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||||
52 NULL);
|
52
|
||||||
53 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
53 if (! gtk_text_buffer_get_modified (tb))
|
||||||
54 gtk_widget_show (dialog);
|
54 return; /* no need to save it */
|
||||||
55 }
|
55 else if (tv->file == NULL)
|
||||||
|
56 tfe_text_view_saveas (tv);
|
||||||
|
57 else if (! G_IS_FILE (tv->file))
|
||||||
|
58 g_error ("TfeTextView: The pointer in this object isn't NULL nor GFile object.\n");
|
||||||
|
59 else
|
||||||
|
60 save_file (tv->file, tb, GTK_WINDOW (win));
|
||||||
|
61 }
|
||||||
|
62
|
||||||
|
63 void
|
||||||
|
64 tfe_text_view_saveas (TfeTextView *tv) {
|
||||||
|
65 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
|
66
|
||||||
|
67 GtkWidget *dialog;
|
||||||
|
68 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||||
|
69
|
||||||
|
70 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
71 "Cancel", GTK_RESPONSE_CANCEL,
|
||||||
|
72 "Save", GTK_RESPONSE_ACCEPT,
|
||||||
|
73 NULL);
|
||||||
|
74 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
||||||
|
75 gtk_widget_show (dialog);
|
||||||
|
76 }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
- 20-56: `Tfe_text_view_save` function.
|
- 1-24: `save_file` function.
|
||||||
- 22: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns.
|
This function is called from `saveas_dialog_response` and `tfe_text_view_save`.
|
||||||
This function is similar to `g_return_val_if_fail` function, but no value is returned because `tfe_text_view_save` doesn't return a value.
|
This function saves the contents of the buffer to the file given as an argument.
|
||||||
- 32-33: If the buffer hasn't modified, then it doesn't need to save it.
|
If error happens, it displays an error message.
|
||||||
So the function returns.
|
- 10-11: Gets the text contents from the buffer.
|
||||||
- 34-35: If `tv->file` is NULL, no file has given yet.
|
- 12-14: Saves the contents to the file.
|
||||||
It calls `tfe_text_view_saveas` which prompts a user to select a file or specify a new file to save.
|
If it's been done without error, set the modified flag to be FALSE.
|
||||||
- 37-38: Gets the contents of the GtkTextBuffer and sets `contents` to point it.
|
This means that the buffer is not modified since it has been saved.
|
||||||
- 39-40: Saves the content to the file.
|
And return TRUE to the caller.
|
||||||
If it succeeds, it resets the modified bit in the GtkTextBuffer.
|
- 15-22: If it's failed to save the contents, displays an error message.
|
||||||
- 42-53: If file writing fails, it assigns NULL to `tv->file`.
|
Creates a message dialog with the error message.
|
||||||
|
Connects the "response" signal to `gtk_window_destroy`, so that the dialog disappears when a user clicked on the button.
|
||||||
|
Shows the window, frees `err` and returns FLASE to the caller.
|
||||||
|
- 26-44: `saveas_dialog_response` function.
|
||||||
|
This is a signal handler for a "response" signal on GtkFileChooserDialog created by `tfe_text_view_saveas` function.
|
||||||
|
This handler analyzes the response and determines whether to save the contents.
|
||||||
|
- 32-44: If the response is `GTK_RESPONSE_ACCEPT`, the user has clicked on the `Save` button. So, it tries to save.
|
||||||
|
- 33-35: Gets the GFile `file` from GtkFileChooserDialog.
|
||||||
|
If it doesn't point GFile, it outputs an error message to the log.
|
||||||
|
- 36-42: Otherwise, it calls `save_file` to save the contents to the file.
|
||||||
|
`tv->file` is changed, but if the old GFile pointed by `tv->file` exists, it is freed in advance.
|
||||||
Emits "change-file" signal.
|
Emits "change-file" signal.
|
||||||
Shows the error message dialog (48-52).
|
- 46-51: `Tfe_text_view_save` function.
|
||||||
Because the handler is `gtk_window_destroy`, the dialog disappears when user clicks on the button in the dialog.
|
- 48: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns.
|
||||||
Frees the GError object.
|
This function is similar to `g_return_val_if_fail` function, but no value is returned because `tfe_text_view_save` doesn't return a value.
|
||||||
- 58-71: `tfe_text_view_saveas` function.
|
- 53-54: If the buffer hasn't modified, then it doesn't need to save it.
|
||||||
|
So the function returns.
|
||||||
|
- 55-56: If `tv->file` is NULL, no file has given yet.
|
||||||
|
It calls `tfe_text_view_saveas` which prompts a user to select a file or specify a new file to save.
|
||||||
|
- 57-58: If `tv->file` doesn't point GFile, somethig bad has happened.
|
||||||
|
Logs an error message.
|
||||||
|
- 59-60: Calls `save_file` and saves the contents to the file.
|
||||||
|
It is possible that `save_file`fails, but no notification will be given to the caller.
|
||||||
|
- 63-76: `tfe_text_view_saveas` function.
|
||||||
It shows GtkFileChooserDialog and prompts the user to choose a file.
|
It shows GtkFileChooserDialog and prompts the user to choose a file.
|
||||||
- 65-68: Generates GtkFileChooserDialog.
|
- 70-73: Creates GtkFileChooserDialog.
|
||||||
The title is "Save file".
|
The title is "Save file".
|
||||||
Transient parent of the dialog is `win`, which is the top level window.
|
Transient parent of the dialog is `win`, which is the top level window.
|
||||||
The action is save mode.
|
The action is save mode.
|
||||||
The buttons are Cancel and Save.
|
The buttons are Cancel and Save.
|
||||||
- 69: connects the "response" signal of the dialog and `saveas_dialog_response` handler.
|
- 74: connects the "response" signal of the dialog and `saveas_dialog_response` handler.
|
||||||
- 1-18: `saveas_dialog_response` signal handler.
|
|
||||||
- 6-16: If the response is `GTK_RESPONSE_ACCEPT`, then it gets a pointer to the GFile object.
|
|
||||||
Then, it sets `tv->file` to point the GFile.
|
|
||||||
And turns on the modified bit of the GtkTextBuffer, emits "change-file" signal.
|
|
||||||
Finally, it calls `tfe_text_view_save` to save the buffer to the file.
|
|
||||||
|
|
||||||
![Saveas process](../image/saveas.png)
|
![Saveas process](../image/saveas.png)
|
||||||
|
|
||||||
When you use GtkFileChooserDialog, you need to divide the program into two parts.
|
When you use GtkFileChooserDialog, you need to divide the program into two parts.
|
||||||
One is are a function which generates GtkFileChooserDialog and the other is a signal handler.
|
One is a function which creates GtkFileChooserDialog and the other is a signal handler.
|
||||||
The function just generates and shows GtkFileChooserDialog.
|
The function just creates and shows GtkFileChooserDialog.
|
||||||
The rest is done by the handler.
|
The rest is done by the handler.
|
||||||
It gets Gfile from GtkFileChooserDialog and saves the buffer to the file by calling `tfe_text_view_save`.
|
It gets Gfile from GtkFileChooserDialog and saves the buffer to the file by calling `tfe_text_view_save`.
|
||||||
|
|
||||||
|
@ -254,15 +288,15 @@ Open function shows GtkFileChooserDialog to users and prompts them to choose a f
|
||||||
Then it reads the file and puts the text to GtkTextBuffer.
|
Then it reads the file and puts the text to GtkTextBuffer.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
void tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
void tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
The parameter `win` is the top window.
|
The parameter `win` is the top level window.
|
||||||
It will be a transient parent window of GtkFileChooserDialog when the dialog is generated..
|
It will be a transient parent window of GtkFileChooserDialog when the dialog is created.
|
||||||
This allows window managers to keep the dialog on top of the parent window, or center the dialog over the parent window.
|
This allows window managers to keep the dialog on top of the parent window, or center the dialog over the parent window.
|
||||||
It is possible to give no parent window to the dialog.
|
It is possible to give no parent window to the dialog.
|
||||||
However, it is encouraged to give a parent window to dialog.
|
However, it is encouraged to give a parent window to dialog.
|
||||||
This function might be called just after `tv` has been generated.
|
This function might be called just after `tv` has been created.
|
||||||
In that case, `tv` has not been incorporated into the widget hierarchy.
|
In that case, `tv` has not been incorporated into the widget hierarchy.
|
||||||
Therefore it is impossible to get the top window from `tv`.
|
Therefore it is impossible to get the top window from `tv`.
|
||||||
That's why the function needs `win` parameter.
|
That's why the function needs `win` parameter.
|
||||||
|
@ -311,13 +345,13 @@ Otherwise probably bad things will happen.
|
||||||
36 }
|
36 }
|
||||||
37
|
37
|
||||||
38 void
|
38 void
|
||||||
39 tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
|
39 tfe_text_view_open (TfeTextView *tv, GtkWindow *win) {
|
||||||
40 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
40 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
41 g_return_if_fail (GTK_IS_WINDOW (win));
|
41 g_return_if_fail (GTK_IS_WINDOW (win));
|
||||||
42
|
42
|
||||||
43 GtkWidget *dialog;
|
43 GtkWidget *dialog;
|
||||||
44
|
44
|
||||||
45 dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
|
45 dialog = gtk_file_chooser_dialog_new ("Open file", win, GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
46 "Cancel", GTK_RESPONSE_CANCEL,
|
46 "Cancel", GTK_RESPONSE_CANCEL,
|
||||||
47 "Open", GTK_RESPONSE_ACCEPT,
|
47 "Open", GTK_RESPONSE_ACCEPT,
|
||||||
48 NULL);
|
48 NULL);
|
||||||
|
@ -326,23 +360,23 @@ Otherwise probably bad things will happen.
|
||||||
51 }
|
51 }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
- 37-50: `tfe_text_view_open` function.
|
- 38-51: `tfe_text_view_open` function.
|
||||||
- 44-47: Generates GtkFileChooserDialog.
|
- 45-48: Creates GtkFileChooserDialog.
|
||||||
The title is "Open file".
|
The title is "Open file".
|
||||||
Transient parent window is the top window of the application, which is given by the caller.
|
Transient parent window is the top level window of the application, which is given by the caller.
|
||||||
The action is open mode.
|
The action is open mode.
|
||||||
The buttons are Cancel and Open.
|
The buttons are Cancel and Open.
|
||||||
- 48: connects the "response" signal of the dialog and `open_dialog_response` signal handler.
|
- 49: connects the "response" signal of the dialog and `open_dialog_response` signal handler.
|
||||||
- 49: Shows the dialog.
|
- 50: Shows the dialog.
|
||||||
- 1-35: `open_dialog_response` signal handler.
|
- 1-36: `open_dialog_response` signal handler.
|
||||||
- 10-11: If the response from GtkFileChooserDialog is not `GTK_RESPONSE_ACCEPT`, which means the user has clicked on the "Cancel" button or close button, then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_CANCEL`.
|
- 10-11: If the response from GtkFileChooserDialog is not `GTK_RESPONSE_ACCEPT`, which means the user has clicked on the "Cancel" button or close button on the header bar, then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_CANCEL`.
|
||||||
- 12-13: Gets a pointer to Gfile by `gtk_file_chooser_get_file`.
|
- 12-14: Gets a pointer to Gfile by `gtk_file_chooser_get_file`.
|
||||||
If it is not GFile, maybe an error occurred.
|
If it doesn't point GFile, maybe an error occurred.
|
||||||
Then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
Then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
||||||
- 14-23: If an error occurs at file reading, then it decreases the reference count of the Gfile, shows a message dialog to report the error to the user and emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
- 15-24: If an error occurs at file reading, then it decreases the reference count of the Gfile, shows a message dialog to report the error to the user and emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
||||||
- 24-33: If the file has successfully read, then the text is inserted to GtkTextBuffer, frees the temporary buffer pointed by `contents` and sets `tv->file` to point the file (no duplication or unref is not necessary).
|
- 25-33: If the file has successfully been read, then the text is inserted to GtkTextBuffer, frees the temporary buffer pointed by `contents` and sets `tv->file` to point the file (no duplication or unref is not necessary).
|
||||||
Then, it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_SUCCESS` and emits "change-file" signal.
|
Then, it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_SUCCESS` and emits "change-file" signal.
|
||||||
- 34: closes GtkFileCooserDialog.
|
- 35: closes GtkFileCooserDialog.
|
||||||
|
|
||||||
Now let's think about the whole process between the other object (caller) and TfeTextView.
|
Now let's think about the whole process between the other object (caller) and TfeTextView.
|
||||||
It is shown in the following diagram and you would think that it is really complicated.
|
It is shown in the following diagram and you would think that it is really complicated.
|
||||||
|
@ -362,7 +396,7 @@ However, in Gtk4, `gtk_dialog_run`is unavailable any more.
|
||||||
|
|
||||||
## Get file function
|
## Get file function
|
||||||
|
|
||||||
`gtk_text_view_get_file` is a simple function show as follows.
|
`gtk_text_view_get_file` is a simple function shown as follows.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
1 GFile *
|
1 GFile *
|
||||||
|
|
|
@ -167,7 +167,7 @@ The return value NULL means that an error has happened.
|
||||||
24
|
24
|
||||||
25 tv = tfe_text_view_new ();
|
25 tv = tfe_text_view_new ();
|
||||||
26 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
26 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
||||||
27 tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
27 tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)));
|
||||||
28 }
|
28 }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
|
246
gfm/sec15.md
246
gfm/sec15.md
|
@ -368,7 +368,7 @@ It is a good practice for you to add more features.
|
||||||
109
|
109
|
||||||
110 tv = tfe_text_view_new ();
|
110 tv = tfe_text_view_new ();
|
||||||
111 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
111 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
||||||
112 tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
112 tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)));
|
||||||
113 }
|
113 }
|
||||||
114
|
114
|
||||||
115 void
|
115 void
|
||||||
|
@ -422,7 +422,7 @@ It is a good practice for you to add more features.
|
||||||
18 tfe_text_view_get_file (TfeTextView *tv);
|
18 tfe_text_view_get_file (TfeTextView *tv);
|
||||||
19
|
19
|
||||||
20 void
|
20 void
|
||||||
21 tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
21 tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
|
||||||
22
|
22
|
||||||
23 void
|
23 void
|
||||||
24 tfe_text_view_save (TfeTextView *tv);
|
24 tfe_text_view_save (TfeTextView *tv);
|
||||||
|
@ -549,129 +549,125 @@ It is a good practice for you to add more features.
|
||||||
105 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
105 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||||
106 if (! G_IS_FILE (file))
|
106 if (! G_IS_FILE (file))
|
||||||
107 g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
107 g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
||||||
108 else {
|
108 else if (save_file(file, tb, GTK_WINDOW (win))) {
|
||||||
109 save_file(file, tb, GTK_WINDOW (win));
|
109 if (G_IS_FILE (tv->file))
|
||||||
110 if (G_IS_FILE (tv->file))
|
110 g_object_unref (tv->file);
|
||||||
111 g_object_unref (tv->file);
|
111 tv->file = file;
|
||||||
112 tv->file = file;
|
112 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||||
113 gtk_text_buffer_set_modified (tb, FALSE);
|
113 }
|
||||||
114 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
114 }
|
||||||
115 }
|
115 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||||
116 }
|
116 }
|
||||||
117 gtk_window_destroy (GTK_WINDOW (dialog));
|
117
|
||||||
118 }
|
118 void
|
||||||
119
|
119 tfe_text_view_save (TfeTextView *tv) {
|
||||||
120 void
|
120 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
121 tfe_text_view_save (TfeTextView *tv) {
|
121
|
||||||
122 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
122 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
123
|
123 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||||
124 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
124
|
||||||
125 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
125 if (! gtk_text_buffer_get_modified (tb))
|
||||||
126
|
126 return; /* no need to save it */
|
||||||
127 if (! gtk_text_buffer_get_modified (tb))
|
127 else if (tv->file == NULL)
|
||||||
128 return; /* no need to save it */
|
128 tfe_text_view_saveas (tv);
|
||||||
129 else if (tv->file == NULL)
|
129 else if (! G_IS_FILE (tv->file))
|
||||||
130 tfe_text_view_saveas (tv);
|
130 g_error ("TfeTextView: The pointer in this object isn't NULL nor GFile object.\n");
|
||||||
131 else if (! G_IS_FILE (tv->file))
|
131 else
|
||||||
132 g_error ("TfeTextView: The pointer in this object isn't NULL nor GFile object.\n");
|
132 save_file (tv->file, tb, GTK_WINDOW (win));
|
||||||
133 else {
|
133 }
|
||||||
134 if (save_file (tv->file, tb, GTK_WINDOW (win)))
|
134
|
||||||
135 gtk_text_buffer_set_modified (tb, FALSE);
|
135 void
|
||||||
136 }
|
136 tfe_text_view_saveas (TfeTextView *tv) {
|
||||||
137 }
|
137 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
138
|
138
|
||||||
139 void
|
139 GtkWidget *dialog;
|
||||||
140 tfe_text_view_saveas (TfeTextView *tv) {
|
140 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||||
141 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
141
|
||||||
142
|
142 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
143 GtkWidget *dialog;
|
143 "Cancel", GTK_RESPONSE_CANCEL,
|
||||||
144 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
144 "Save", GTK_RESPONSE_ACCEPT,
|
||||||
145
|
145 NULL);
|
||||||
146 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
146 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
||||||
147 "Cancel", GTK_RESPONSE_CANCEL,
|
147 gtk_widget_show (dialog);
|
||||||
148 "Save", GTK_RESPONSE_ACCEPT,
|
148 }
|
||||||
149 NULL);
|
149
|
||||||
150 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
150 GtkWidget *
|
||||||
151 gtk_widget_show (dialog);
|
151 tfe_text_view_new_with_file (GFile *file) {
|
||||||
152 }
|
152 g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||||
153
|
153
|
||||||
154 GtkWidget *
|
154 GtkWidget *tv;
|
||||||
155 tfe_text_view_new_with_file (GFile *file) {
|
155 GtkTextBuffer *tb;
|
||||||
156 g_return_val_if_fail (G_IS_FILE (file), NULL);
|
156 char *contents;
|
||||||
157
|
157 gsize length;
|
||||||
158 GtkWidget *tv;
|
158
|
||||||
159 GtkTextBuffer *tb;
|
159 if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
|
||||||
160 char *contents;
|
160 return NULL;
|
||||||
161 gsize length;
|
161
|
||||||
162
|
162 tv = tfe_text_view_new();
|
||||||
163 if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
|
163 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
164 return NULL;
|
164 gtk_text_buffer_set_text (tb, contents, length);
|
||||||
165
|
165 g_free (contents);
|
||||||
166 tv = tfe_text_view_new();
|
166 TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
|
||||||
167 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
167 return tv;
|
||||||
168 gtk_text_buffer_set_text (tb, contents, length);
|
168 }
|
||||||
169 g_free (contents);
|
169
|
||||||
170 TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
|
170 static void
|
||||||
171 return tv;
|
171 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||||
172 }
|
172 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
173
|
173 GFile *file;
|
||||||
174 static void
|
174 char *contents;
|
||||||
175 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
175 gsize length;
|
||||||
176 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
176 GtkWidget *message_dialog;
|
||||||
177 GFile *file;
|
177 GError *err = NULL;
|
||||||
178 char *contents;
|
178
|
||||||
179 gsize length;
|
179 if (response != GTK_RESPONSE_ACCEPT)
|
||||||
180 GtkWidget *message_dialog;
|
180 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
|
||||||
181 GError *err = NULL;
|
181 else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)))) {
|
||||||
182
|
182 g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
||||||
183 if (response != GTK_RESPONSE_ACCEPT)
|
183 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||||
184 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
|
184 } else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
|
||||||
185 else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)))) {
|
185 if (G_IS_FILE (file))
|
||||||
186 g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
186 g_object_unref (file);
|
||||||
187 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
187 message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
|
||||||
188 } else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
|
188 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||||
189 if (G_IS_FILE (file))
|
189 "%s.\n", err->message);
|
||||||
190 g_object_unref (file);
|
190 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||||
191 message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
|
191 gtk_widget_show (message_dialog);
|
||||||
192 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
192 g_error_free (err);
|
||||||
193 "%s.\n", err->message);
|
193 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||||
194 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
194 } else {
|
||||||
195 gtk_widget_show (message_dialog);
|
195 gtk_text_buffer_set_text (tb, contents, length);
|
||||||
196 g_error_free (err);
|
196 g_free (contents);
|
||||||
197 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
197 if (G_IS_FILE (tv->file))
|
||||||
198 } else {
|
198 g_object_unref (tv->file);
|
||||||
199 gtk_text_buffer_set_text (tb, contents, length);
|
199 tv->file = file;
|
||||||
200 g_free (contents);
|
200 gtk_text_buffer_set_modified (tb, FALSE);
|
||||||
201 if (G_IS_FILE (tv->file))
|
201 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
|
||||||
202 g_object_unref (tv->file);
|
202 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||||
203 tv->file = file;
|
203 }
|
||||||
204 gtk_text_buffer_set_modified (tb, FALSE);
|
204 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||||
205 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
|
205 }
|
||||||
206 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
206
|
||||||
207 }
|
207 void
|
||||||
208 gtk_window_destroy (GTK_WINDOW (dialog));
|
208 tfe_text_view_open (TfeTextView *tv, GtkWindow *win) {
|
||||||
209 }
|
209 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
210
|
210 g_return_if_fail (GTK_IS_WINDOW (win));
|
||||||
211 void
|
211
|
||||||
212 tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
|
212 GtkWidget *dialog;
|
||||||
213 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
213
|
||||||
214 g_return_if_fail (GTK_IS_WINDOW (win));
|
214 dialog = gtk_file_chooser_dialog_new ("Open file", win, GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
215
|
215 "Cancel", GTK_RESPONSE_CANCEL,
|
||||||
216 GtkWidget *dialog;
|
216 "Open", GTK_RESPONSE_ACCEPT,
|
||||||
217
|
217 NULL);
|
||||||
218 dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
|
218 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
|
||||||
219 "Cancel", GTK_RESPONSE_CANCEL,
|
219 gtk_widget_show (dialog);
|
||||||
220 "Open", GTK_RESPONSE_ACCEPT,
|
220 }
|
||||||
221 NULL);
|
221
|
||||||
222 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
|
222 GtkWidget *
|
||||||
223 gtk_widget_show (dialog);
|
223 tfe_text_view_new (void) {
|
||||||
224 }
|
224 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||||
225
|
225 }
|
||||||
226 GtkWidget *
|
226
|
||||||
227 tfe_text_view_new (void) {
|
|
||||||
228 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
|
||||||
229 }
|
|
||||||
230
|
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
## Total number of lines, words and characters
|
## Total number of lines, words and characters
|
||||||
|
@ -682,12 +678,12 @@ $ LANG=C wc tfe5/meson.build tfe5/tfeapplication.c tfe5/tfe.gresource.xml tfe5/t
|
||||||
97 301 3159 tfe5/tfeapplication.c
|
97 301 3159 tfe5/tfeapplication.c
|
||||||
6 9 153 tfe5/tfe.gresource.xml
|
6 9 153 tfe5/tfe.gresource.xml
|
||||||
4 6 87 tfe5/tfe.h
|
4 6 87 tfe5/tfe.h
|
||||||
140 373 3580 tfe5/tfenotebook.c
|
140 374 3593 tfe5/tfenotebook.c
|
||||||
15 21 241 tfe5/tfenotebook.h
|
15 21 241 tfe5/tfenotebook.h
|
||||||
230 686 8144 tfetextview/tfetextview.c
|
226 677 8023 tfetextview/tfetextview.c
|
||||||
35 60 701 tfetextview/tfetextview.h
|
35 60 701 tfetextview/tfetextview.h
|
||||||
61 100 2073 tfe5/tfe.ui
|
61 100 2073 tfe5/tfe.ui
|
||||||
598 1573 18432 total
|
594 1565 18324 total
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Up: [Readme.md](../Readme.md), Prev: [Section 22](sec22.md)
|
Up: [Readme.md](../Readme.md), Prev: [Section 22](sec22.md), Next: [Section 24](sec24.md)
|
||||||
|
|
||||||
# Tiny turtle graphics interpreter
|
# Tiny turtle graphics interpreter
|
||||||
|
|
||||||
|
@ -1926,4 +1926,4 @@ Lately, lots of source codes are in the internet.
|
||||||
Maybe reading source codes are the most useful for programmers.
|
Maybe reading source codes are the most useful for programmers.
|
||||||
|
|
||||||
|
|
||||||
Up: [Readme.md](../Readme.md), Prev: [Section 22](sec22.md)
|
Up: [Readme.md](../Readme.md), Prev: [Section 22](sec22.md), Next: [Section 24](sec24.md)
|
||||||
|
|
|
@ -19,7 +19,7 @@ However, first of all, I'd like to focus on the object TfeTextView.
|
||||||
It is a child object of GtkTextView and has a new member `file` in it.
|
It is a child object of GtkTextView and has a new member `file` in it.
|
||||||
The important thing is to manage the Gfile object pointed by `file`.
|
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 creating (or initializing) TfeTextView?
|
||||||
- What is necessary to GFile when destructing TfeTextView?
|
- What is necessary to GFile when destructing TfeTextView?
|
||||||
- TfeTextView should read/write a file by itself or not?
|
- TfeTextView should read/write a file by itself or not?
|
||||||
- How it communicates with objects outside?
|
- How it communicates with objects outside?
|
||||||
|
@ -88,7 +88,7 @@ struct _GtkTextView
|
||||||
In each structure, its parent instance is declared at the top of members.
|
In each structure, its parent instance is declared at the top of members.
|
||||||
So, every ancestors is included in the child instance.
|
So, every ancestors is included in the child instance.
|
||||||
This is very important.
|
This is very important.
|
||||||
It guarantees a child widget to derive all the features from ancestors.
|
It guarantees a child widget to inherit all the features from ancestors.
|
||||||
The structure of `TfeTextView` is like the following diagram.
|
The structure of `TfeTextView` is like the following diagram.
|
||||||
|
|
||||||
![The structure of the instance TfeTextView](../image/TfeTextView.png){width=14.39cm height=2.16cm}
|
![The structure of the instance TfeTextView](../image/TfeTextView.png){width=14.39cm height=2.16cm}
|
||||||
|
@ -104,7 +104,7 @@ tfetextview/tfetextview.c tfe_text_view_new
|
||||||
|
|
||||||
When this function is run, the following procedure is gone through.
|
When this function is run, the following procedure is gone through.
|
||||||
|
|
||||||
1. Initialize GObject part in TfeTextView instance.
|
1. Initialize GObject (GInitiallyUnowned) part in TfeTextView instance.
|
||||||
2. Initialize GtkWidget part in TfeTextView instance.
|
2. Initialize GtkWidget part in TfeTextView instance.
|
||||||
3. Initialize GtkTextView part in TfeTextView instance.
|
3. Initialize GtkTextView part in TfeTextView instance.
|
||||||
4. Initialize TfeTextView part in TfeTextView instance.
|
4. Initialize TfeTextView part in TfeTextView instance.
|
||||||
|
@ -123,7 +123,7 @@ This function just initializes `tv->file` to be `NULL`.
|
||||||
|
|
||||||
## Functions and Classes
|
## Functions and Classes
|
||||||
|
|
||||||
In Gtk, all objects derived from GObject have class and instance.
|
In Gtk, all objects derived from GObject have class and instance (except abstract object).
|
||||||
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.
|
||||||
Each object can have more than one instance.
|
Each object can have more than one instance.
|
||||||
Those instances have the same structure.
|
Those instances have the same structure.
|
||||||
|
@ -205,14 +205,14 @@ It is illustrated in the following diagram.
|
||||||
## Destruction of TfeTextView
|
## Destruction of TfeTextView
|
||||||
|
|
||||||
Every Object derived from GObject has a reference count.
|
Every Object derived from GObject has a reference count.
|
||||||
If an object A refers an object B, then A keeps a pointer to B in A and at the same time increases the reference count of B by one with the function `g_object_ref (B)`.
|
If an object A refers to an object B, then A keeps a pointer to B in A and at the same time increases the reference count of B by one with the function `g_object_ref (B)`.
|
||||||
If A doesn't need B any longer, then A discards the pointer to B (usually it is done by assigning NULL to the pointer) and decreases the reference count of B by one with the function `g_object_unref (B)`.
|
If A doesn't need B any longer, then A discards the pointer to B (usually it is done by assigning NULL to the pointer) and decreases the reference count of B by one with the function `g_object_unref (B)`.
|
||||||
|
|
||||||
If two objects A and B refer to C, then the reference count of C is two.
|
If two objects A and B refer to C, then the reference count of C is two.
|
||||||
If A no longer needs C, A discards the pointer to C and decreases the reference count in C by one.
|
If A no longer needs C, A discards the pointer to C and decreases the reference count in C by one.
|
||||||
Now the reference count of C is one.
|
Now the reference count of C is one.
|
||||||
In the same way, if B no longer needs C, B discards the pointer to C and decreases the reference count in C by one.
|
In the same way, if B no longer needs C, B discards the pointer to C and decreases the reference count in C by one.
|
||||||
At this moment, no object refers C and the reference count of C is zero.
|
At this moment, no object refers to C and the reference count of C is zero.
|
||||||
This means C is no longer useful.
|
This means C is no longer useful.
|
||||||
Then C destructs itself and finally the memories allocated to C is freed.
|
Then C destructs itself and finally the memories allocated to C is freed.
|
||||||
|
|
||||||
|
|
113
src/sec12.src.md
113
src/sec12.src.md
|
@ -20,26 +20,26 @@ tfetextview//tfetextview.h
|
||||||
- 1,2,35: Thanks to these three lines, the following lines are included only once.
|
- 1,2,35: Thanks to these three lines, the following lines are included only once.
|
||||||
- 4: Includes gtk4 header files.
|
- 4: Includes gtk4 header files.
|
||||||
The header file `gtk4` also has the same mechanism to avoid including it multiple times.
|
The header file `gtk4` also has the same mechanism to avoid including it multiple times.
|
||||||
- 6-7: These two lines define TfeTextView.
|
- 6-7: These two lines define TfeTextView type, its class structure and some useful macros.
|
||||||
- 9-15: A definition of the value of the parameter of "open-response" signal.
|
- 9-15: A definition of the value of the parameter of "open-response" signal.
|
||||||
- 17-33: Declaration of public functions on GtkTextView.
|
- 17-33: Declarations of public functions on TfeTextView.
|
||||||
|
|
||||||
## Functions to generate TfeTextView object
|
## Functions to create TfeTextView object
|
||||||
|
|
||||||
TfeTextView Object is generated by `tfe_text_view_new` or `tfe_text_view_new_with_file`.
|
TfeTextView Object is created with `tfe_text_view_new` or `tfe_text_view_new_with_file`.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
GtkWidget *tfe_text_view_new (void);
|
GtkWidget *tfe_text_view_new (void);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
`tfe_text_view_new` just generates a new TfeTextView object and returns the pointer to the new object.
|
`tfe_text_view_new` just creates a new TfeTextView object and returns the pointer to the new object.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
GtkWidget *tfe_text_view_new_with_file (GFile *file);
|
GtkWidget *tfe_text_view_new_with_file (GFile *file);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
`tfe_text_view_new_with_file` is given a Gfile object as the argument and it loads the file into the GtkTextBuffer object, then returns the pointer to the new object.
|
`tfe_text_view_new_with_file` is given a Gfile object as the argument and it loads the file into the GtkTextBuffer object, then returns the pointer to the new object.
|
||||||
If an error occurs during the generation process, NULL is returned.
|
If an error occurs during the creation process, NULL is returned.
|
||||||
|
|
||||||
Each function is defined as follows.
|
Each function is defined as follows.
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ 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.
|
||||||
- 10-11: If an error occurs when reading the file, then return NULL.
|
- 10-11: If an error occurs when reading the file, then return NULL.
|
||||||
- 13: Calls the function `tfe_text_view_new`.
|
- 13: Calls the function `tfe_text_view_new`.
|
||||||
The function generates TfeTextView instance and returns the pointer to the instance.
|
The function creates TfeTextView instance and returns the pointer to the instance.
|
||||||
- 14: Gets the pointer to GtkTextBuffer corresponds to `tv`.
|
- 14: Gets the pointer to GtkTextBuffer corresponds to `tv`.
|
||||||
The pointer is assigned to `tb`
|
The pointer is assigned to `tb`
|
||||||
- 15: Assigns the contents read from the file to GtkTextBuffer pointed by `tb`.
|
- 15: Assigns the contents read from the file to GtkTextBuffer pointed by `tb`.
|
||||||
|
@ -80,7 +80,7 @@ void tfe_text_view_save (TfeTextView *tv)
|
||||||
|
|
||||||
The function `save` writes the contents in GtkTextBuffer to a file specified by `tv->file`.
|
The function `save` writes the contents in GtkTextBuffer to a file specified by `tv->file`.
|
||||||
If `tv->file` is NULL, then it shows GtkFileChooserDialog and prompts the user to choose a file to save.
|
If `tv->file` is NULL, then it shows GtkFileChooserDialog and prompts the user to choose a file to save.
|
||||||
Then it saves the contents to the file and sets `tv->file` to point the GFile instance of the file.
|
Then it saves the contents to the file and sets `tv->file` to point the GFile of the file.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
void tfe_text_view_saveas (TfeTextView *tv)
|
void tfe_text_view_saveas (TfeTextView *tv)
|
||||||
|
@ -92,43 +92,56 @@ If an error occurs, it is shown to the user through the message dialog.
|
||||||
The error is managed only in the TfeTextView instance and no information is notified to the caller.
|
The error is managed only in the TfeTextView instance and no information is notified to the caller.
|
||||||
|
|
||||||
@@@include
|
@@@include
|
||||||
tfetextview/tfetextview.c saveas_dialog_response tfe_text_view_save tfe_text_view_saveas
|
tfetextview/tfetextview.c save_file saveas_dialog_response tfe_text_view_save tfe_text_view_saveas
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
- 20-56: `Tfe_text_view_save` function.
|
- 1-24: `save_file` function.
|
||||||
- 22: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns.
|
This function is called from `saveas_dialog_response` and `tfe_text_view_save`.
|
||||||
This function is similar to `g_return_val_if_fail` function, but no value is returned because `tfe_text_view_save` doesn't return a value.
|
This function saves the contents of the buffer to the file given as an argument.
|
||||||
- 32-33: If the buffer hasn't modified, then it doesn't need to save it.
|
If error happens, it displays an error message.
|
||||||
So the function returns.
|
- 10-11: Gets the text contents from the buffer.
|
||||||
- 34-35: If `tv->file` is NULL, no file has given yet.
|
- 12-14: Saves the contents to the file.
|
||||||
It calls `tfe_text_view_saveas` which prompts a user to select a file or specify a new file to save.
|
If it's been done without error, set the modified flag to be FALSE.
|
||||||
- 37-38: Gets the contents of the GtkTextBuffer and sets `contents` to point it.
|
This means that the buffer is not modified since it has been saved.
|
||||||
- 39-40: Saves the content to the file.
|
And return TRUE to the caller.
|
||||||
If it succeeds, it resets the modified bit in the GtkTextBuffer.
|
- 15-22: If it's failed to save the contents, displays an error message.
|
||||||
- 42-53: If file writing fails, it assigns NULL to `tv->file`.
|
Creates a message dialog with the error message.
|
||||||
|
Connects the "response" signal to `gtk_window_destroy`, so that the dialog disappears when a user clicked on the button.
|
||||||
|
Shows the window, frees `err` and returns FLASE to the caller.
|
||||||
|
- 26-44: `saveas_dialog_response` function.
|
||||||
|
This is a signal handler for a "response" signal on GtkFileChooserDialog created by `tfe_text_view_saveas` function.
|
||||||
|
This handler analyzes the response and determines whether to save the contents.
|
||||||
|
- 32-44: If the response is `GTK_RESPONSE_ACCEPT`, the user has clicked on the `Save` button. So, it tries to save.
|
||||||
|
- 33-35: Gets the GFile `file` from GtkFileChooserDialog.
|
||||||
|
If it doesn't point GFile, it outputs an error message to the log.
|
||||||
|
- 36-42: Otherwise, it calls `save_file` to save the contents to the file.
|
||||||
|
`tv->file` is changed, but if the old GFile pointed by `tv->file` exists, it is freed in advance.
|
||||||
Emits "change-file" signal.
|
Emits "change-file" signal.
|
||||||
Shows the error message dialog (48-52).
|
- 46-51: `Tfe_text_view_save` function.
|
||||||
Because the handler is `gtk_window_destroy`, the dialog disappears when user clicks on the button in the dialog.
|
- 48: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns.
|
||||||
Frees the GError object.
|
This function is similar to `g_return_val_if_fail` function, but no value is returned because `tfe_text_view_save` doesn't return a value.
|
||||||
- 58-71: `tfe_text_view_saveas` function.
|
- 53-54: If the buffer hasn't modified, then it doesn't need to save it.
|
||||||
|
So the function returns.
|
||||||
|
- 55-56: If `tv->file` is NULL, no file has given yet.
|
||||||
|
It calls `tfe_text_view_saveas` which prompts a user to select a file or specify a new file to save.
|
||||||
|
- 57-58: If `tv->file` doesn't point GFile, somethig bad has happened.
|
||||||
|
Logs an error message.
|
||||||
|
- 59-60: Calls `save_file` and saves the contents to the file.
|
||||||
|
It is possible that `save_file`fails, but no notification will be given to the caller.
|
||||||
|
- 63-76: `tfe_text_view_saveas` function.
|
||||||
It shows GtkFileChooserDialog and prompts the user to choose a file.
|
It shows GtkFileChooserDialog and prompts the user to choose a file.
|
||||||
- 65-68: Generates GtkFileChooserDialog.
|
- 70-73: Creates GtkFileChooserDialog.
|
||||||
The title is "Save file".
|
The title is "Save file".
|
||||||
Transient parent of the dialog is `win`, which is the top level window.
|
Transient parent of the dialog is `win`, which is the top level window.
|
||||||
The action is save mode.
|
The action is save mode.
|
||||||
The buttons are Cancel and Save.
|
The buttons are Cancel and Save.
|
||||||
- 69: connects the "response" signal of the dialog and `saveas_dialog_response` handler.
|
- 74: connects the "response" signal of the dialog and `saveas_dialog_response` handler.
|
||||||
- 1-18: `saveas_dialog_response` signal handler.
|
|
||||||
- 6-16: If the response is `GTK_RESPONSE_ACCEPT`, then it gets a pointer to the GFile object.
|
|
||||||
Then, it sets `tv->file` to point the GFile.
|
|
||||||
And turns on the modified bit of the GtkTextBuffer, emits "change-file" signal.
|
|
||||||
Finally, it calls `tfe_text_view_save` to save the buffer to the file.
|
|
||||||
|
|
||||||
![Saveas process](../image/saveas.png){width=10.7cm height=5.16cm}
|
![Saveas process](../image/saveas.png){width=10.7cm height=5.16cm}
|
||||||
|
|
||||||
When you use GtkFileChooserDialog, you need to divide the program into two parts.
|
When you use GtkFileChooserDialog, you need to divide the program into two parts.
|
||||||
One is are a function which generates GtkFileChooserDialog and the other is a signal handler.
|
One is a function which creates GtkFileChooserDialog and the other is a signal handler.
|
||||||
The function just generates and shows GtkFileChooserDialog.
|
The function just creates and shows GtkFileChooserDialog.
|
||||||
The rest is done by the handler.
|
The rest is done by the handler.
|
||||||
It gets Gfile from GtkFileChooserDialog and saves the buffer to the file by calling `tfe_text_view_save`.
|
It gets Gfile from GtkFileChooserDialog and saves the buffer to the file by calling `tfe_text_view_save`.
|
||||||
|
|
||||||
|
@ -138,15 +151,15 @@ Open function shows GtkFileChooserDialog to users and prompts them to choose a f
|
||||||
Then it reads the file and puts the text to GtkTextBuffer.
|
Then it reads the file and puts the text to GtkTextBuffer.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
void tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
void tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
The parameter `win` is the top window.
|
The parameter `win` is the top level window.
|
||||||
It will be a transient parent window of GtkFileChooserDialog when the dialog is generated..
|
It will be a transient parent window of GtkFileChooserDialog when the dialog is created.
|
||||||
This allows window managers to keep the dialog on top of the parent window, or center the dialog over the parent window.
|
This allows window managers to keep the dialog on top of the parent window, or center the dialog over the parent window.
|
||||||
It is possible to give no parent window to the dialog.
|
It is possible to give no parent window to the dialog.
|
||||||
However, it is encouraged to give a parent window to dialog.
|
However, it is encouraged to give a parent window to dialog.
|
||||||
This function might be called just after `tv` has been generated.
|
This function might be called just after `tv` has been created.
|
||||||
In that case, `tv` has not been incorporated into the widget hierarchy.
|
In that case, `tv` has not been incorporated into the widget hierarchy.
|
||||||
Therefore it is impossible to get the top window from `tv`.
|
Therefore it is impossible to get the top window from `tv`.
|
||||||
That's why the function needs `win` parameter.
|
That's why the function needs `win` parameter.
|
||||||
|
@ -160,23 +173,23 @@ Otherwise probably bad things will happen.
|
||||||
tfetextview/tfetextview.c open_dialog_response tfe_text_view_open
|
tfetextview/tfetextview.c open_dialog_response tfe_text_view_open
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
- 37-50: `tfe_text_view_open` function.
|
- 38-51: `tfe_text_view_open` function.
|
||||||
- 44-47: Generates GtkFileChooserDialog.
|
- 45-48: Creates GtkFileChooserDialog.
|
||||||
The title is "Open file".
|
The title is "Open file".
|
||||||
Transient parent window is the top window of the application, which is given by the caller.
|
Transient parent window is the top level window of the application, which is given by the caller.
|
||||||
The action is open mode.
|
The action is open mode.
|
||||||
The buttons are Cancel and Open.
|
The buttons are Cancel and Open.
|
||||||
- 48: connects the "response" signal of the dialog and `open_dialog_response` signal handler.
|
- 49: connects the "response" signal of the dialog and `open_dialog_response` signal handler.
|
||||||
- 49: Shows the dialog.
|
- 50: Shows the dialog.
|
||||||
- 1-35: `open_dialog_response` signal handler.
|
- 1-36: `open_dialog_response` signal handler.
|
||||||
- 10-11: If the response from GtkFileChooserDialog is not `GTK_RESPONSE_ACCEPT`, which means the user has clicked on the "Cancel" button or close button, then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_CANCEL`.
|
- 10-11: If the response from GtkFileChooserDialog is not `GTK_RESPONSE_ACCEPT`, which means the user has clicked on the "Cancel" button or close button on the header bar, then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_CANCEL`.
|
||||||
- 12-13: Gets a pointer to Gfile by `gtk_file_chooser_get_file`.
|
- 12-14: Gets a pointer to Gfile by `gtk_file_chooser_get_file`.
|
||||||
If it is not GFile, maybe an error occurred.
|
If it doesn't point GFile, maybe an error occurred.
|
||||||
Then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
Then it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
||||||
- 14-23: If an error occurs at file reading, then it decreases the reference count of the Gfile, shows a message dialog to report the error to the user and emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
- 15-24: If an error occurs at file reading, then it decreases the reference count of the Gfile, shows a message dialog to report the error to the user and emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_ERROR`.
|
||||||
- 24-33: If the file has successfully read, then the text is inserted to GtkTextBuffer, frees the temporary buffer pointed by `contents` and sets `tv->file` to point the file (no duplication or unref is not necessary).
|
- 25-33: If the file has successfully been read, then the text is inserted to GtkTextBuffer, frees the temporary buffer pointed by `contents` and sets `tv->file` to point the file (no duplication or unref is not necessary).
|
||||||
Then, it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_SUCCESS` and emits "change-file" signal.
|
Then, it emits "open-response" signal with the parameter `TFE_OPEN_RESPONSE_SUCCESS` and emits "change-file" signal.
|
||||||
- 34: closes GtkFileCooserDialog.
|
- 35: closes GtkFileCooserDialog.
|
||||||
|
|
||||||
Now let's think about the whole process between the other object (caller) and TfeTextView.
|
Now let's think about the whole process between the other object (caller) and TfeTextView.
|
||||||
It is shown in the following diagram and you would think that it is really complicated.
|
It is shown in the following diagram and you would think that it is really complicated.
|
||||||
|
@ -196,7 +209,7 @@ However, in Gtk4, `gtk_dialog_run`is unavailable any more.
|
||||||
|
|
||||||
## Get file function
|
## Get file function
|
||||||
|
|
||||||
`gtk_text_view_get_file` is a simple function show as follows.
|
`gtk_text_view_get_file` is a simple function shown as follows.
|
||||||
|
|
||||||
@@@include
|
@@@include
|
||||||
tfetextview/tfetextview.c tfe_text_view_get_file
|
tfetextview/tfetextview.c tfe_text_view_get_file
|
||||||
|
|
|
@ -109,7 +109,7 @@ notebook_page_open (GtkNotebook *nb) {
|
||||||
|
|
||||||
tv = tfe_text_view_new ();
|
tv = tfe_text_view_new ();
|
||||||
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
||||||
tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -179,7 +179,7 @@ notebook_page_open (GtkNotebook *nb) {
|
||||||
|
|
||||||
tv = tfe_text_view_new ();
|
tv = tfe_text_view_new ();
|
||||||
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
||||||
tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -180,7 +180,7 @@ notebook_page_open (GtkNotebook *nb) {
|
||||||
|
|
||||||
tv = tfe_text_view_new ();
|
tv = tfe_text_view_new ();
|
||||||
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
||||||
tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -105,12 +105,10 @@ saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||||
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))
|
||||||
g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile object.\n");
|
||||||
else {
|
else if (save_file(file, tb, GTK_WINDOW (win))) {
|
||||||
save_file(file, tb, GTK_WINDOW (win));
|
|
||||||
if (G_IS_FILE (tv->file))
|
if (G_IS_FILE (tv->file))
|
||||||
g_object_unref (tv->file);
|
g_object_unref (tv->file);
|
||||||
tv->file = file;
|
tv->file = file;
|
||||||
gtk_text_buffer_set_modified (tb, FALSE);
|
|
||||||
g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,10 +128,8 @@ tfe_text_view_save (TfeTextView *tv) {
|
||||||
tfe_text_view_saveas (tv);
|
tfe_text_view_saveas (tv);
|
||||||
else if (! G_IS_FILE (tv->file))
|
else if (! G_IS_FILE (tv->file))
|
||||||
g_error ("TfeTextView: The pointer in this object isn't NULL nor GFile object.\n");
|
g_error ("TfeTextView: The pointer in this object isn't NULL nor GFile object.\n");
|
||||||
else {
|
else
|
||||||
if (save_file (tv->file, tb, GTK_WINDOW (win)))
|
save_file (tv->file, tb, GTK_WINDOW (win));
|
||||||
gtk_text_buffer_set_modified (tb, FALSE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -209,13 +205,13 @@ open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
|
tfe_text_view_open (TfeTextView *tv, GtkWindow *win) {
|
||||||
g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||||
g_return_if_fail (GTK_IS_WINDOW (win));
|
g_return_if_fail (GTK_IS_WINDOW (win));
|
||||||
|
|
||||||
GtkWidget *dialog;
|
GtkWidget *dialog;
|
||||||
|
|
||||||
dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
|
dialog = gtk_file_chooser_dialog_new ("Open file", win, GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
"Cancel", GTK_RESPONSE_CANCEL,
|
"Cancel", GTK_RESPONSE_CANCEL,
|
||||||
"Open", GTK_RESPONSE_ACCEPT,
|
"Open", GTK_RESPONSE_ACCEPT,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
|
@ -18,7 +18,7 @@ GFile *
|
||||||
tfe_text_view_get_file (TfeTextView *tv);
|
tfe_text_view_get_file (TfeTextView *tv);
|
||||||
|
|
||||||
void
|
void
|
||||||
tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
|
||||||
|
|
||||||
void
|
void
|
||||||
tfe_text_view_save (TfeTextView *tv);
|
tfe_text_view_save (TfeTextView *tv);
|
||||||
|
|
|
@ -36,7 +36,7 @@ run_cb (GtkWidget *btnr) {
|
||||||
|
|
||||||
void
|
void
|
||||||
open_cb (GtkWidget *btno) {
|
open_cb (GtkWidget *btno) {
|
||||||
tfe_text_view_open (TFE_TEXT_VIEW (tv), win);
|
tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (win));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue