Modify section 8 and 9.

This commit is contained in:
Toshio Sekiya 2021-06-16 21:32:44 +09:00
parent 8eaf6064a8
commit cbd454c85b
11 changed files with 313 additions and 285 deletions

View file

@ -9,16 +9,16 @@ Now we go on to rewrite it and make a very simple editor.
Its source file name is tfe1.c (text file editor 1).
GtkTextView originally has a feature of multi line editing.
Therefore, we don't need to rewrite the program from scratch.
Therefore, we don't need to write the program from scratch.
We just add two things to the file viewer.
- Static memory is needed to store a pointer to GFile.
- We need to implement file write function.
- Memory to store a pointer to the GFile instance.
- A function to write the file.
A couple of ways are possible to get memories to keep GFile.
- Use global variables.
- make a child object so that it can extend the memories for the GFile object.
- make a child object so that it can extend the instance memory for the GFile object.
Using global variables is easy to implement.
Define a sufficient size array of pointers to GFile.
@ -28,13 +28,13 @@ For example,
GFile *f[20];
~~~
And `f[i]` corresponds to i-th GtkNotebookPage.
And `f[i]` corresponds to the i-th GtkNotebookPage.
However, there are two problems.
One is the size of the array.
If a user gives arguments more than that, bad thing may happen.
If a user gives arguments more than that (20 in the example above), it is impossible to store all the pointers to the GFile instances.
The other is the difficulty of maintenance of the program.
It is a small program so far.
However, if you continue developing it, then its size grows bigger and bigger.
However, if you continue developing it, then the size of the program grows bigger and bigger.
Generally speaking, the bigger the program size, the more difficult to maintain global variables.
Making child object is a good idea in terms of maintenance.
@ -43,7 +43,7 @@ What we are thinking about now is "child object".
A child object includes its parent object.
And a child object derives everything from the parent object.
![Child widget of GtkTextView](../image/child.png)
![Child object of GtkTextView](../image/child.png)
We will define TfeTextView as a child object of GtkTextView.
It has everything that GtkTextView has.
@ -52,8 +52,9 @@ And important thing is that TfeTextView can have a memory to keep a pointer to G
However, to understand the general theory about Gobject is very hard especially for beginners.
So, I will just show you the way how to write the code and avoid the theoretical side in the next subsection.
If you want to know about GObject system, refer to [GObject tutorial](https://github.com/ToshioCP/Gobject-tutorial).
## How to define a child widget of GtkTextView
## How to define a child object of GtkTextView
Let's define TfeTextView object which is a child object of GtkTextView.
First, look at the program below.
@ -98,6 +99,7 @@ If you are curious about the background theory of this program, It's very good f
Because knowing the theory is very important for you to program GTK applications.
Look at [GObject API reference](https://developer.gnome.org/gobject/stable/).
All you need is described in it.
Or, refer to [GObject tutorial](https://github.com/ToshioCP/Gobject-tutorial).
However, it's a tough journey especially for beginners.
For now, you don't need to know such difficult theory.
Just remember the instructions below.
@ -107,8 +109,8 @@ Tfe and TextView.
Tfe is called prefix, namespace or module.
TextView is called object.
- There are three patterns.
TfeTextView (camel case), tfe\_text\_view (this is used to write functions) and TFE\_TEXT\_VIEW (This is used to write casts).
- First, define TFE\_TYPE\_TEXT\_VIEW as tfe\_text\_view\_get\_type ().
TfeTextView (camel case), tfe\_text\_view (this is used to write functions) and TFE\_TEXT\_VIEW (This is used to cast a pointer to point TfeTextView type).
- First, define TFE\_TYPE\_TEXT\_VIEW macro as tfe\_text\_view\_get\_type ().
The name is always (prefix)\_TYPE\_(object) and the letters are upper case.
And the replacement text is always (prefix)\_(object)\_get\_type () and the letters are lower case.
- Next, use G\_DECLARE\_FINAL\_TYPE macro.
@ -118,31 +120,30 @@ The underscore is necessary.
The first member is the parent object.
Notice this is not a pointer but the object itself.
The second member and after are members of the child object.
TfeTextView structure has a pointer to GFile as a member.
TfeTextView structure has a pointer to a GFile instance as a member.
- Use G\_DEFINE\_TYPE macro.
The arguments are the child object name in camel case, lower case with underscore and parent object type (prefix)\_TYPE\_(module).
- Define instance init function (tfe\_text\_view\_init).
Usually you don't need to do anything.
- Define class init function (tfe\_text\_view\_class\_init).
You don't need to do anything in this widget.
You don't need to do anything in this object.
- Write function codes you want to add (tfe\_text\_view\_set\_file and tfe\_text\_view\_get\_file).
`tv` is a pointer to TfeTextView object instance which is a C-structure declared with the tag \_TfeTextView.
So, the structure has a member `file` as a pointer to GFile.
`tv` is a pointer to the TfeTextView object instance which is a C-structure declared with the tag \_TfeTextView.
So, the structure has a member `file` as a pointer to a GFile instance.
`tv->file = f` is an assignment of `f` to a member `file` of the structure pointed by `tv`.
This is an example how to use the extended memory in a child widget.
- Write object generation function.
- Write a function to create an instance.
Its name is (prefix)\_(object)\_new.
If the parent object function needs parameters, this function also need them.
You sometimes might want to add some parameters.
It's your choice.
Use g\_object\_new function to generate the child widget.
Use g\_object\_new function to create the instance.
The arguments are (prefix)\_TYPE\_(object), a list to initialize properties and NULL.
In this code no property needs to be initialized.
And the return value must be casted to GtkWidget.
And the return value is casted to GtkWidget.
This program is not perfect.
It has some problems.
But I don't discuss them now.
It will be modified later.
## Close-request signal
@ -150,7 +151,7 @@ It will be modified later.
Imagine that you use this editor.
First, you run the editor with arguments.
The arguments are filenames.
The editor reads the files and shows its window with the text of files in it.
The editor reads the files and shows the window with the text of files in it.
Then you edit the text.
After you finish editing, you exit the editor.
The editor updates files just before the window closes.
@ -158,7 +159,7 @@ The editor updates files just before the window closes.
GtkWindow emits "close-request" signal before it closes.
We connect the signal and the handler `before_close`.
A handler is a C function.
When a function is connected to a certain signal, we call it handler.
When a function is connected to a certain signal, we call it a handler.
The function `before_close` is invoked when the signal "close-request" is emitted.
~~~C
@ -171,46 +172,54 @@ The program of `before_close` is as follows.
~~~C
1 static gboolean
2 before_close (GtkWindow *win, GtkWidget *nb) {
3 GtkWidget *scr;
4 GtkWidget *tv;
5 GFile *file;
6 GtkTextBuffer *tb;
7 GtkTextIter start_iter;
8 GtkTextIter end_iter;
9 char *contents;
10 unsigned int n;
11 unsigned int i;
12
13 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
14 for (i = 0; i < n; ++i) {
15 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
16 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
17 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
18 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
19 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
20 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
21 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
22 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
23 }
24 return FALSE;
25 }
2 before_close (GtkWindow *win, gpointer user_data) {
3 GtkWidget *nb = GTK_WIDGET (user_data);
4 GtkWidget *scr;
5 GtkWidget *tv;
6 GFile *file;
7 char *pathname;
8 GtkTextBuffer *tb;
9 GtkTextIter start_iter;
10 GtkTextIter end_iter;
11 char *contents;
12 unsigned int n;
13 unsigned int i;
14
15 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
16 for (i = 0; i < n; ++i) {
17 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
18 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
19 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
20 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
21 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
22 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
23 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) {
24 pathname = g_file_get_path (file);
25 g_print ("ERROR : Can't save %s.", pathname);
26 g_free (pathname);
27 }
28 g_free (contents);
29 }
30 return FALSE;
31 }
~~~
The numbers on the left of items are line numbers in the source code.
- 13: Gets the number of pages `nb` has.
- 14-23: For loop with regard to the index to each pages.
- 15-17: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
The pointer was stored when `on_open` handler had run. It will be shown later.
- 18-20: Gets GtkTextBuffer and contents. `start_iter` and `end_iter` are iterators of the buffer.
- 15: Gets the number of pages `nb` has.
- 16-29: For loop with regard to the index to each pages.
- 17-19: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
The pointer was stored when `app_open` handler had run. It will be shown later.
- 20-22: Gets GtkTextBuffer and contents. `start_iter` and `end_iter` are iterators of the buffer.
I don't want to explain them now because it would take a lot of time.
Just remember these lines for the present.
- 21: Writes the file.
- 23-27: Writes the contents to the file.
If it fails, it outputs an error message.
- 28: Frees `contents`.
## Source code of tfe1.c
Now I will show you all the source code of `tfe1`.c.
Now I will show you all the source code of `tfe1.c`.
~~~C
1 #include <gtk/gtk.h>
@ -254,113 +263,120 @@ Now I will show you all the source code of `tfe1`.c.
39 /* ---------- end of the definition of TfeTextView ---------- */
40
41 static gboolean
42 before_close (GtkWindow *win, GtkWidget *nb) {
43 GtkWidget *scr;
44 GtkWidget *tv;
45 GFile *file;
46 GtkTextBuffer *tb;
47 GtkTextIter start_iter;
48 GtkTextIter end_iter;
49 char *contents;
50 unsigned int n;
51 unsigned int i;
52
53 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
54 for (i = 0; i < n; ++i) {
55 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
56 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
57 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
58 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
59 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
60 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
61 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
62 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
63 }
64 return FALSE;
65 }
66
67 static void
68 on_activate (GApplication *app, gpointer user_data) {
69 g_print ("You need to give filenames as arguments.\n");
70 }
71
72 static void
73 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
74 GtkWidget *win;
75 GtkWidget *nb;
76 GtkWidget *lab;
77 GtkNotebookPage *nbp;
78 GtkWidget *scr;
79 GtkWidget *tv;
80 GtkTextBuffer *tb;
81 char *contents;
82 gsize length;
83 char *filename;
84 int i;
85
86 win = gtk_application_window_new (GTK_APPLICATION (app));
87 gtk_window_set_title (GTK_WINDOW (win), "file editor");
88 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
89 gtk_window_maximize (GTK_WINDOW (win));
90
91 nb = gtk_notebook_new ();
92 gtk_window_set_child (GTK_WINDOW (win), nb);
93
94 for (i = 0; i < n_files; i++) {
95 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
96 scr = gtk_scrolled_window_new ();
97 tv = tfe_text_view_new ();
98 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
99 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
100 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
101
102 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
103 gtk_text_buffer_set_text (tb, contents, length);
104 g_free (contents);
105 filename = g_file_get_basename (files[i]);
106 lab = gtk_label_new (filename);
107 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
108 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
109 g_object_set (nbp, "tab-expand", TRUE, NULL);
110 g_free (filename);
111 } else {
112 filename = g_file_get_path (files[i]);
113 g_print ("No such file: %s.\n", filename);
114 g_free (filename);
115 }
116 }
117 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
118 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
119 gtk_widget_show (win);
120 } else
121 gtk_window_destroy (GTK_WINDOW (win));
122 }
123
124 int
125 main (int argc, char **argv) {
126 GtkApplication *app;
127 int stat;
42 before_close (GtkWindow *win, gpointer user_data) {
43 GtkWidget *nb = GTK_WIDGET (user_data);
44 GtkWidget *scr;
45 GtkWidget *tv;
46 GFile *file;
47 char *pathname;
48 GtkTextBuffer *tb;
49 GtkTextIter start_iter;
50 GtkTextIter end_iter;
51 char *contents;
52 unsigned int n;
53 unsigned int i;
54
55 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
56 for (i = 0; i < n; ++i) {
57 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
58 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
59 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
60 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
61 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
62 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
63 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) {
64 pathname = g_file_get_path (file);
65 g_print ("ERROR : Can't save %s.", pathname);
66 g_free (pathname);
67 }
68 g_free (contents);
69 }
70 return FALSE;
71 }
72
73 static void
74 app_activate (GApplication *app, gpointer user_data) {
75 g_print ("You need to give filenames as arguments.\n");
76 }
77
78 static void
79 app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
80 GtkWidget *win;
81 GtkWidget *nb;
82 GtkWidget *lab;
83 GtkNotebookPage *nbp;
84 GtkWidget *scr;
85 GtkWidget *tv;
86 GtkTextBuffer *tb;
87 char *contents;
88 gsize length;
89 char *filename;
90 int i;
91
92 win = gtk_application_window_new (GTK_APPLICATION (app));
93 gtk_window_set_title (GTK_WINDOW (win), "file editor");
94 gtk_window_maximize (GTK_WINDOW (win));
95
96 nb = gtk_notebook_new ();
97 gtk_window_set_child (GTK_WINDOW (win), nb);
98
99 for (i = 0; i < n_files; i++) {
100 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
101 scr = gtk_scrolled_window_new ();
102 tv = tfe_text_view_new ();
103 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
104 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
105 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
106
107 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
108 gtk_text_buffer_set_text (tb, contents, length);
109 g_free (contents);
110 filename = g_file_get_basename (files[i]);
111 lab = gtk_label_new (filename);
112 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
113 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
114 g_object_set (nbp, "tab-expand", TRUE, NULL);
115 g_free (filename);
116 } else if ((filename = g_file_get_path (files[i])) != NULL) {
117 g_print ("No such file: %s.\n", filename);
118 g_free (filename);
119 } else
120 g_print ("No valid file is given\n");
121 }
122 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
123 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
124 gtk_widget_show (win);
125 } else
126 gtk_window_destroy (GTK_WINDOW (win));
127 }
128
129 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
130 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
131 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
132 stat =g_application_run (G_APPLICATION (app), argc, argv);
133 g_object_unref (app);
134 return stat;
135 }
136
129 int
130 main (int argc, char **argv) {
131 GtkApplication *app;
132 int stat;
133
134 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
135 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
136 g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
137 stat =g_application_run (G_APPLICATION (app), argc, argv);
138 g_object_unref (app);
139 return stat;
140 }
~~~
- 102: Sets the pointer to GFile into TfeTextView.
- 107: Sets the pointer to GFile into TfeTextView.
`files[i]` is a pointer to GFile structure.
It will be freed by the system. So you need to copy it.
`g_file_dup` duplicates the given GFile structure.
- 118: Connects "close-request" signal and `before_close` handler.
- 123: Connects "close-request" signal and `before_close` handler.
The fourth argument is called user data and it is given to the signal handler.
So, `nb` is given to `before_close` as the second argument.
Now compile and run it.
Type `./a.out somefile` and make sure that the file is modified.
There's a sample file in the directory `tfe`.
Type `./a.out taketori.txt`.
Modify the contents and close the window.
Make sure that the file is modified.
Now we got a very simple editor.
It's not smart.

View file

@ -5,7 +5,7 @@ Up: [Readme.md](../Readme.md), Prev: [Section 8](sec8.md), Next: [Section 10](s
## New, open and save button
We made the simplest editor in the previous section.
It reads the files in `on_open` function at start-up and writes them when closing the window.
It reads the files in `app_open` function at start-up and writes them when closing the window.
It works but is not good.
It is better to make "New", "Open", "Save" and "Close" buttons.
This section describes how to put those buttons into the window.
@ -14,11 +14,11 @@ Signals and handlers will be explained later.
![Screenshot of the file editor](../image/screenshot_tfe2.png)
The screenshot above shows the layout.
The function `on_open` in the source code `tfe2.c` is as follows.
The function `app_open` in the source code `tfe2.c` is as follows.
~~~C
1 static void
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
2 app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
3 GtkWidget *win;
4 GtkWidget *nb;
5 GtkWidget *lab;
@ -92,11 +92,11 @@ The function `on_open` in the source code `tfe2.c` is as follows.
73 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
74 g_object_set (nbp, "tab-expand", TRUE, NULL);
75 g_free (filename);
76 } else {
77 filename = g_file_get_path (files[i]);
78 g_print ("No such file: %s.\n", filename);
79 g_free (filename);
80 }
76 } else if ((filename = g_file_get_path (files[i])) != NULL) {
77 g_print ("No such file: %s.\n", filename);
78 g_free (filename);
79 } else
80 g_print ("No valid file is given\n");
81 }
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
83 gtk_widget_show (win);
@ -107,25 +107,25 @@ The function `on_open` in the source code `tfe2.c` is as follows.
The point is how to build the window.
- 25-27: Generates GtkApplicationWindow and sets the title and default size.
- 29-30: Generates GtkBox `boxv`.
- 25-27: Creates a GtkApplicationWindow instance and sets the title and default size.
- 29-30: Creates a GtkBox instance `boxv`.
It is a vertical box and a child of GtkApplicationWindow.
It has two children.
The first child is a horizontal box includes buttons.
The second child is GtkNotebook.
- 32-33: Generates GtkBox `boxh` and appends it to 'boxv' as a first child.
- 35-40: Generates three dummy labels.
The first child is a horizontal box.
The second child is a GtkNotebook.
- 32-33: Creates a GtkBox instance `boxh` and appends it to `boxv` as a first child.
- 35-40: Creates three dummy labels.
The labels `dmy1` and `dmy3` has a character width of ten.
The other label `dmy2` has hexpand property which is set to be TRUE.
This makes the label expands horizontally as long as possible.
- 41-44: Generates four buttons.
- 41-44: Creates four buttons.
- 46-52: Appends these GtkLabel and GtkButton to `boxh`.
- 54-57: Generates GtkNotebook and sets hexpand and vexpand properties TRUE.
- 54-57: Creates a GtkNotebook instance and sets hexpand and vexpand properties TRUE.
This makes it expand horizontally and vertically as big as possible.
It is appended to `boxv` as the second child.
The number of lines is 33(=57-25+1) to build the widgets.
And we needed many variables (boxv, boxh, dmy1 ...).
And we needed many variables (`boxv`, `boxh`, `dmy1`, ...).
Most of them aren't necessary except building the widgets.
Are there any good solution to reduce these work?
@ -199,7 +199,7 @@ First, let's look at the ui file `tfe3.ui` that defines a structure of the widge
59 </interface>
~~~
This is coded with XML structure.
The structure of this file is XML.
Constructs beginning with `<` and ending with `>` are called tags.
And there are two types of tags, start tag and end tag.
For example, `<interface>` is a start tag and `</interface>` is an end tag.
@ -209,15 +209,15 @@ Some tags, for example, object tags can have a class and id attributes in the st
- 1: The first line is XML declaration.
It specifies that the version of XML is 1.0 and the encoding is UTF-8.
Even if the line is left out, GtkBuilder builds objects from the ui file.
But ui files must use UTF-8 encoding, or GtkBuilder can't recognize it and fatal error occurs.
But ui files must use UTF-8 encoding, or GtkBuilder can't recognize it and a fatal error occurs.
- 3-6: An object with `GtkApplicationWindow` class and `win` id is defined.
This is the top level window.
And the three properties of the window are defined.
`title` property is "file editor", `default-width` property is 400 and `default-height` property is 300.
- 7: child tag means a child of the object above.
For example, line 7 tells us that GtkBox object which id is "boxv" is a child of `win`.
`title` property is "file editor", `default-width` property is 600 and `default-height` property is 400.
- 7: child tag means a child of the widget above.
For example, line 7 tells us that GtkBox object which id is "boxv" is a child widget of `win`.
Compare this ui file and the lines 25-57 in the source code of `on_open` function.
Compare this ui file and the lines 25-57 in the source code of `app_open` function.
Those two describe the same structure of widgets.
You can check the ui file with `gtk4-builder-tool`.
@ -227,7 +227,7 @@ If the ui file includes some syntactical error, `gtk4-builder-tool` prints the e
- `gtk4-builder-tool simplify <ui file name>` simplifies the ui file and prints the result.
If `--replace` option is given, it replaces the ui file with the simplified one.
If the ui file specifies a value of property but it is default, then it will be removed.
Anf some values are simplified.
And some values are simplified.
For example, "TRUE"and "FALSE" becomes "1" and "0" respectively.
However, "TRUE" or "FALSE" is better for maintenance.
@ -247,7 +247,7 @@ nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
~~~
The function `gtk_builder_new_from_file` reads the file given as an argument.
Then, it builds the widgets and pointers to them, creates GtkBuilder object and put the pointers in it.
Then, it builds the widgets and creates GtkBuilder object.
The function `gtk_builder_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file.
All the widgets are connected based on the parent-children relationship described in the ui file.
We only need `win` and `nb` for the program after this, so we don't need to take out any other widgets.
@ -314,15 +314,15 @@ $ cd tfe; diff tfe2.c tfe3.c
> app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
~~~
`60,103c61,65` means 42 (=103-60+1) lines change to 5 (=65-61+1) lines.
Therefore 37 lines are reduced.
`60,103c61,65` means 44 (=103-60+1) lines are changed to 5 (=65-61+1) lines.
Therefore, 39 lines are reduced.
Using ui file not only shortens C source files, but also makes the widgets' structure clear.
Now I'll show you `on_open` function in the C source code `tfe3.c`.
Now I'll show you `app_open` function in the C file `tfe3.c`.
~~~C
1 static void
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
2 app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
3 GtkWidget *win;
4 GtkWidget *nb;
5 GtkWidget *lab;
@ -358,11 +358,11 @@ Now I'll show you `on_open` function in the C source code `tfe3.c`.
35 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
36 g_object_set (nbp, "tab-expand", TRUE, NULL);
37 g_free (filename);
38 } else {
39 filename = g_file_get_path (files[i]);
40 g_print ("No such file: %s.\n", filename);
41 g_free (filename);
42 }
38 } else if ((filename = g_file_get_path (files[i])) != NULL) {
39 g_print ("No such file: %s.\n", filename);
40 g_free (filename);
41 } else
42 g_print ("No valid file is given\n");
43 }
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
45 gtk_widget_show (win);
@ -373,12 +373,11 @@ Now I'll show you `on_open` function in the C source code `tfe3.c`.
The whole source code of `tfe3.c` is stored in [src/tfe](https://github.com/ToshioCP/Gtk4-tutorial/tree/main/src/tfe) directory.
If you want to see it, click the link above.
You can also get the source files below.
### Using ui string
GtkBuilder can build widgets using string.
Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file.
Use the function `gtk_builder_new_from_string` instead of `gtk_builder_new_from_file`.
~~~C
char *uistring;
@ -406,7 +405,7 @@ The disadvantage is that writing C string is a bit bothersome because of the dou
If you want to use this method, you should write a script that transforms ui file into C-string.
- Add backslash before each double quote.
- Add double quote at the left and right.
- Add double quotes at the left and right of the string in each line.
### Using Gresource

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 21 KiB

BIN
image/child.xcf Normal file

Binary file not shown.

View file

@ -7,16 +7,16 @@ Now we go on to rewrite it and make a very simple editor.
Its source file name is tfe1.c (text file editor 1).
GtkTextView originally has a feature of multi line editing.
Therefore, we don't need to rewrite the program from scratch.
Therefore, we don't need to write the program from scratch.
We just add two things to the file viewer.
- Static memory is needed to store a pointer to GFile.
- We need to implement file write function.
- Memory to store a pointer to the GFile instance.
- A function to write the file.
A couple of ways are possible to get memories to keep GFile.
- Use global variables.
- make a child object so that it can extend the memories for the GFile object.
- make a child object so that it can extend the instance memory for the GFile object.
Using global variables is easy to implement.
Define a sufficient size array of pointers to GFile.
@ -26,13 +26,13 @@ For example,
GFile *f[20];
~~~
And `f[i]` corresponds to i-th GtkNotebookPage.
And `f[i]` corresponds to the i-th GtkNotebookPage.
However, there are two problems.
One is the size of the array.
If a user gives arguments more than that, bad thing may happen.
If a user gives arguments more than that (20 in the example above), it is impossible to store all the pointers to the GFile instances.
The other is the difficulty of maintenance of the program.
It is a small program so far.
However, if you continue developing it, then its size grows bigger and bigger.
However, if you continue developing it, then the size of the program grows bigger and bigger.
Generally speaking, the bigger the program size, the more difficult to maintain global variables.
Making child object is a good idea in terms of maintenance.
@ -41,7 +41,7 @@ What we are thinking about now is "child object".
A child object includes its parent object.
And a child object derives everything from the parent object.
![Child widget of GtkTextView](../image/child.png){width=9.675cm height=4.89cm}
![Child object of GtkTextView](../image/child.png){width=9.675cm height=4.89cm}
We will define TfeTextView as a child object of GtkTextView.
It has everything that GtkTextView has.
@ -50,8 +50,9 @@ And important thing is that TfeTextView can have a memory to keep a pointer to G
However, to understand the general theory about Gobject is very hard especially for beginners.
So, I will just show you the way how to write the code and avoid the theoretical side in the next subsection.
If you want to know about GObject system, refer to [GObject tutorial](https://github.com/ToshioCP/Gobject-tutorial).
## How to define a child widget of GtkTextView
## How to define a child object of GtkTextView
Let's define TfeTextView object which is a child object of GtkTextView.
First, look at the program below.
@ -96,6 +97,7 @@ If you are curious about the background theory of this program, It's very good f
Because knowing the theory is very important for you to program GTK applications.
Look at [GObject API reference](https://developer.gnome.org/gobject/stable/).
All you need is described in it.
Or, refer to [GObject tutorial](https://github.com/ToshioCP/Gobject-tutorial).
However, it's a tough journey especially for beginners.
For now, you don't need to know such difficult theory.
Just remember the instructions below.
@ -105,8 +107,8 @@ Tfe and TextView.
Tfe is called prefix, namespace or module.
TextView is called object.
- There are three patterns.
TfeTextView (camel case), tfe\_text\_view (this is used to write functions) and TFE\_TEXT\_VIEW (This is used to write casts).
- First, define TFE\_TYPE\_TEXT\_VIEW as tfe\_text\_view\_get\_type ().
TfeTextView (camel case), tfe\_text\_view (this is used to write functions) and TFE\_TEXT\_VIEW (This is used to cast a pointer to point TfeTextView type).
- First, define TFE\_TYPE\_TEXT\_VIEW macro as tfe\_text\_view\_get\_type ().
The name is always (prefix)\_TYPE\_(object) and the letters are upper case.
And the replacement text is always (prefix)\_(object)\_get\_type () and the letters are lower case.
- Next, use G\_DECLARE\_FINAL\_TYPE macro.
@ -116,31 +118,30 @@ The underscore is necessary.
The first member is the parent object.
Notice this is not a pointer but the object itself.
The second member and after are members of the child object.
TfeTextView structure has a pointer to GFile as a member.
TfeTextView structure has a pointer to a GFile instance as a member.
- Use G\_DEFINE\_TYPE macro.
The arguments are the child object name in camel case, lower case with underscore and parent object type (prefix)\_TYPE\_(module).
- Define instance init function (tfe\_text\_view\_init).
Usually you don't need to do anything.
- Define class init function (tfe\_text\_view\_class\_init).
You don't need to do anything in this widget.
You don't need to do anything in this object.
- Write function codes you want to add (tfe\_text\_view\_set\_file and tfe\_text\_view\_get\_file).
`tv` is a pointer to TfeTextView object instance which is a C-structure declared with the tag \_TfeTextView.
So, the structure has a member `file` as a pointer to GFile.
`tv` is a pointer to the TfeTextView object instance which is a C-structure declared with the tag \_TfeTextView.
So, the structure has a member `file` as a pointer to a GFile instance.
`tv->file = f` is an assignment of `f` to a member `file` of the structure pointed by `tv`.
This is an example how to use the extended memory in a child widget.
- Write object generation function.
- Write a function to create an instance.
Its name is (prefix)\_(object)\_new.
If the parent object function needs parameters, this function also need them.
You sometimes might want to add some parameters.
It's your choice.
Use g\_object\_new function to generate the child widget.
Use g\_object\_new function to create the instance.
The arguments are (prefix)\_TYPE\_(object), a list to initialize properties and NULL.
In this code no property needs to be initialized.
And the return value must be casted to GtkWidget.
And the return value is casted to GtkWidget.
This program is not perfect.
It has some problems.
But I don't discuss them now.
It will be modified later.
## Close-request signal
@ -148,7 +149,7 @@ It will be modified later.
Imagine that you use this editor.
First, you run the editor with arguments.
The arguments are filenames.
The editor reads the files and shows its window with the text of files in it.
The editor reads the files and shows the window with the text of files in it.
Then you edit the text.
After you finish editing, you exit the editor.
The editor updates files just before the window closes.
@ -156,7 +157,7 @@ The editor updates files just before the window closes.
GtkWindow emits "close-request" signal before it closes.
We connect the signal and the handler `before_close`.
A handler is a C function.
When a function is connected to a certain signal, we call it handler.
When a function is connected to a certain signal, we call it a handler.
The function `before_close` is invoked when the signal "close-request" is emitted.
~~~C
@ -173,33 +174,38 @@ tfe/tfe1.c before_close
The numbers on the left of items are line numbers in the source code.
- 13: Gets the number of pages `nb` has.
- 14-23: For loop with regard to the index to each pages.
- 15-17: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
The pointer was stored when `on_open` handler had run. It will be shown later.
- 18-20: Gets GtkTextBuffer and contents. `start_iter` and `end_iter` are iterators of the buffer.
- 15: Gets the number of pages `nb` has.
- 16-29: For loop with regard to the index to each pages.
- 17-19: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
The pointer was stored when `app_open` handler had run. It will be shown later.
- 20-22: Gets GtkTextBuffer and contents. `start_iter` and `end_iter` are iterators of the buffer.
I don't want to explain them now because it would take a lot of time.
Just remember these lines for the present.
- 21: Writes the file.
- 23-27: Writes the contents to the file.
If it fails, it outputs an error message.
- 28: Frees `contents`.
## Source code of tfe1.c
Now I will show you all the source code of `tfe1`.c.
Now I will show you all the source code of `tfe1.c`.
@@@include
tfe/tfe1.c
@@@
- 102: Sets the pointer to GFile into TfeTextView.
- 107: Sets the pointer to GFile into TfeTextView.
`files[i]` is a pointer to GFile structure.
It will be freed by the system. So you need to copy it.
`g_file_dup` duplicates the given GFile structure.
- 118: Connects "close-request" signal and `before_close` handler.
- 123: Connects "close-request" signal and `before_close` handler.
The fourth argument is called user data and it is given to the signal handler.
So, `nb` is given to `before_close` as the second argument.
Now compile and run it.
Type `./a.out somefile` and make sure that the file is modified.
There's a sample file in the directory `tfe`.
Type `./a.out taketori.txt`.
Modify the contents and close the window.
Make sure that the file is modified.
Now we got a very simple editor.
It's not smart.

View file

@ -3,7 +3,7 @@
## New, open and save button
We made the simplest editor in the previous section.
It reads the files in `on_open` function at start-up and writes them when closing the window.
It reads the files in `app_open` function at start-up and writes them when closing the window.
It works but is not good.
It is better to make "New", "Open", "Save" and "Close" buttons.
This section describes how to put those buttons into the window.
@ -12,33 +12,33 @@ Signals and handlers will be explained later.
![Screenshot of the file editor](../image/screenshot_tfe2.png){width=9.3cm height=6.825cm}
The screenshot above shows the layout.
The function `on_open` in the source code `tfe2.c` is as follows.
The function `app_open` in the source code `tfe2.c` is as follows.
@@@include
tfe/tfe2.c on_open
tfe/tfe2.c app_open
@@@
The point is how to build the window.
- 25-27: Generates GtkApplicationWindow and sets the title and default size.
- 29-30: Generates GtkBox `boxv`.
- 25-27: Creates a GtkApplicationWindow instance and sets the title and default size.
- 29-30: Creates a GtkBox instance `boxv`.
It is a vertical box and a child of GtkApplicationWindow.
It has two children.
The first child is a horizontal box includes buttons.
The second child is GtkNotebook.
- 32-33: Generates GtkBox `boxh` and appends it to 'boxv' as a first child.
- 35-40: Generates three dummy labels.
The first child is a horizontal box.
The second child is a GtkNotebook.
- 32-33: Creates a GtkBox instance `boxh` and appends it to `boxv` as a first child.
- 35-40: Creates three dummy labels.
The labels `dmy1` and `dmy3` has a character width of ten.
The other label `dmy2` has hexpand property which is set to be TRUE.
This makes the label expands horizontally as long as possible.
- 41-44: Generates four buttons.
- 41-44: Creates four buttons.
- 46-52: Appends these GtkLabel and GtkButton to `boxh`.
- 54-57: Generates GtkNotebook and sets hexpand and vexpand properties TRUE.
- 54-57: Creates a GtkNotebook instance and sets hexpand and vexpand properties TRUE.
This makes it expand horizontally and vertically as big as possible.
It is appended to `boxv` as the second child.
The number of lines is 33(=57-25+1) to build the widgets.
And we needed many variables (boxv, boxh, dmy1 ...).
And we needed many variables (`boxv`, `boxh`, `dmy1`, ...).
Most of them aren't necessary except building the widgets.
Are there any good solution to reduce these work?
@ -54,7 +54,7 @@ First, let's look at the ui file `tfe3.ui` that defines a structure of the widge
tfe/tfe3.ui
@@@
This is coded with XML structure.
The structure of this file is XML.
Constructs beginning with `<` and ending with `>` are called tags.
And there are two types of tags, start tag and end tag.
For example, `<interface>` is a start tag and `</interface>` is an end tag.
@ -64,15 +64,15 @@ Some tags, for example, object tags can have a class and id attributes in the st
- 1: The first line is XML declaration.
It specifies that the version of XML is 1.0 and the encoding is UTF-8.
Even if the line is left out, GtkBuilder builds objects from the ui file.
But ui files must use UTF-8 encoding, or GtkBuilder can't recognize it and fatal error occurs.
But ui files must use UTF-8 encoding, or GtkBuilder can't recognize it and a fatal error occurs.
- 3-6: An object with `GtkApplicationWindow` class and `win` id is defined.
This is the top level window.
And the three properties of the window are defined.
`title` property is "file editor", `default-width` property is 400 and `default-height` property is 300.
- 7: child tag means a child of the object above.
For example, line 7 tells us that GtkBox object which id is "boxv" is a child of `win`.
`title` property is "file editor", `default-width` property is 600 and `default-height` property is 400.
- 7: child tag means a child of the widget above.
For example, line 7 tells us that GtkBox object which id is "boxv" is a child widget of `win`.
Compare this ui file and the lines 25-57 in the source code of `on_open` function.
Compare this ui file and the lines 25-57 in the source code of `app_open` function.
Those two describe the same structure of widgets.
You can check the ui file with `gtk4-builder-tool`.
@ -82,7 +82,7 @@ If the ui file includes some syntactical error, `gtk4-builder-tool` prints the e
- `gtk4-builder-tool simplify <ui file name>` simplifies the ui file and prints the result.
If `--replace` option is given, it replaces the ui file with the simplified one.
If the ui file specifies a value of property but it is default, then it will be removed.
Anf some values are simplified.
And some values are simplified.
For example, "TRUE"and "FALSE" becomes "1" and "0" respectively.
However, "TRUE" or "FALSE" is better for maintenance.
@ -102,7 +102,7 @@ nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
~~~
The function `gtk_builder_new_from_file` reads the file given as an argument.
Then, it builds the widgets and pointers to them, creates GtkBuilder object and put the pointers in it.
Then, it builds the widgets and creates GtkBuilder object.
The function `gtk_builder_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file.
All the widgets are connected based on the parent-children relationship described in the ui file.
We only need `win` and `nb` for the program after this, so we don't need to take out any other widgets.
@ -112,24 +112,23 @@ This reduces lines in the C source file.
cd tfe; diff tfe2.c tfe3.c
@@@
`60,103c61,65` means 42 (=103-60+1) lines change to 5 (=65-61+1) lines.
Therefore 37 lines are reduced.
`60,103c61,65` means 44 (=103-60+1) lines are changed to 5 (=65-61+1) lines.
Therefore, 39 lines are reduced.
Using ui file not only shortens C source files, but also makes the widgets' structure clear.
Now I'll show you `on_open` function in the C source code `tfe3.c`.
Now I'll show you `app_open` function in the C file `tfe3.c`.
@@@include
tfe/tfe3.c on_open
tfe/tfe3.c app_open
@@@
The whole source code of `tfe3.c` is stored in [src/tfe](https://github.com/ToshioCP/Gtk4-tutorial/tree/main/src/tfe) directory.
If you want to see it, click the link above.
You can also get the source files below.
### Using ui string
GtkBuilder can build widgets using string.
Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file.
Use the function `gtk_builder_new_from_string` instead of `gtk_builder_new_from_file`.
~~~C
char *uistring;
@ -157,7 +156,7 @@ The disadvantage is that writing C string is a bit bothersome because of the dou
If you want to use this method, you should write a script that transforms ui file into C-string.
- Add backslash before each double quote.
- Add double quote at the left and right.
- Add double quotes at the left and right of the string in each line.
### Using Gresource

4
src/tfe/taketori.txt Normal file
View file

@ -0,0 +1,4 @@
Once upon a time, there was an old man who was called Taketori-no-Okina. It is a japanese word that means a man whose work is making bamboo baskets.
One day, he went into a mountain and found a shining bamboo. "What a mysterious bamboo it is!," he said. He cut it, then there was a small cute baby girl in it. The girl was shining faintly. He thought this baby girl is a gift from Heaven and took her home.
His wife was surprized at his tale. They were very happy because they had no children.

View file

@ -39,10 +39,12 @@ tfe_text_view_new (void) {
/* ---------- end of the definition of TfeTextView ---------- */
static gboolean
before_close (GtkWindow *win, GtkWidget *nb) {
before_close (GtkWindow *win, gpointer user_data) {
GtkWidget *nb = GTK_WIDGET (user_data);
GtkWidget *scr;
GtkWidget *tv;
GFile *file;
char *pathname;
GtkTextBuffer *tb;
GtkTextIter start_iter;
GtkTextIter end_iter;
@ -58,19 +60,23 @@ before_close (GtkWindow *win, GtkWidget *nb) {
tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
g_print ("ERROR : Can't save %s.", g_file_get_path (file));
if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) {
pathname = g_file_get_path (file);
g_print ("ERROR : Can't save %s.", pathname);
g_free (pathname);
}
g_free (contents);
}
return FALSE;
}
static void
on_activate (GApplication *app, gpointer user_data) {
app_activate (GApplication *app, gpointer user_data) {
g_print ("You need to give filenames as arguments.\n");
}
static void
on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
GtkWidget *win;
GtkWidget *nb;
GtkWidget *lab;
@ -85,7 +91,6 @@ on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer
win = gtk_application_window_new (GTK_APPLICATION (app));
gtk_window_set_title (GTK_WINDOW (win), "file editor");
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
gtk_window_maximize (GTK_WINDOW (win));
nb = gtk_notebook_new ();
@ -108,11 +113,11 @@ on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
g_object_set (nbp, "tab-expand", TRUE, NULL);
g_free (filename);
} else {
filename = g_file_get_path (files[i]);
g_print ("No such file: %s.\n", filename);
g_free (filename);
}
} else if ((filename = g_file_get_path (files[i])) != NULL) {
g_print ("No such file: %s.\n", filename);
g_free (filename);
} else
g_print ("No valid file is given\n");
}
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
@ -127,10 +132,9 @@ main (int argc, char **argv) {
int stat;
app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
stat =g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;
}

View file

@ -39,12 +39,12 @@ tfe_text_view_new (void) {
/* ---------- end of the definition of TfeTextView ---------- */
static void
on_activate (GApplication *app, gpointer user_data) {
app_activate (GApplication *app, gpointer user_data) {
g_print ("You need a filename argument.\n");
}
static void
on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
GtkWidget *win;
GtkWidget *nb;
GtkWidget *lab;
@ -118,11 +118,11 @@ on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
g_object_set (nbp, "tab-expand", TRUE, NULL);
g_free (filename);
} else {
filename = g_file_get_path (files[i]);
g_print ("No such file: %s.\n", filename);
g_free (filename);
}
} else if ((filename = g_file_get_path (files[i])) != NULL) {
g_print ("No such file: %s.\n", filename);
g_free (filename);
} else
g_print ("No valid file is given\n");
}
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
gtk_widget_show (win);
@ -136,8 +136,8 @@ main (int argc, char **argv) {
int stat;
app = gtk_application_new ("com.github.ToshioCP.tfe2", G_APPLICATION_HANDLES_OPEN);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
stat =g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;

View file

@ -39,12 +39,12 @@ tfe_text_view_new (void) {
/* ---------- end of the definition of TfeTextView ---------- */
static void
on_activate (GApplication *app, gpointer user_data) {
app_activate (GApplication *app, gpointer user_data) {
g_print ("You need a filename argument.\n");
}
static void
on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
GtkWidget *win;
GtkWidget *nb;
GtkWidget *lab;
@ -80,11 +80,11 @@ on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
g_object_set (nbp, "tab-expand", TRUE, NULL);
g_free (filename);
} else {
filename = g_file_get_path (files[i]);
g_print ("No such file: %s.\n", filename);
g_free (filename);
}
} else if ((filename = g_file_get_path (files[i])) != NULL) {
g_print ("No such file: %s.\n", filename);
g_free (filename);
} else
g_print ("No valid file is given\n");
}
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
gtk_widget_show (win);
@ -98,8 +98,8 @@ main (int argc, char **argv) {
int stat;
app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
stat =g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;

View file

@ -39,12 +39,12 @@ tfe_text_view_new (void) {
/* ---------- end of the definition of TfeTextView ---------- */
static void
on_activate (GApplication *app, gpointer user_data) {
app_activate (GApplication *app, gpointer user_data) {
g_print ("You need a filename argument.\n");
}
static void
on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
GtkWidget *win;
GtkWidget *nb;
GtkWidget *lab;
@ -80,11 +80,11 @@ on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
g_object_set (nbp, "tab-expand", TRUE, NULL);
g_free (filename);
} else {
filename = g_file_get_path (files[i]);
g_print ("No such file: %s.\n", filename);
g_free (filename);
}
} else if ((filename = g_file_get_path (files[i])) != NULL) {
g_print ("No such file: %s.\n", filename);
g_free (filename);
} else
g_print ("No valid file is given\n");
}
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
gtk_widget_show (win);
@ -98,8 +98,8 @@ main (int argc, char **argv) {
int stat;
app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
stat =g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;