mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
Modify section 8 and 9.
This commit is contained in:
parent
8eaf6064a8
commit
cbd454c85b
11 changed files with 313 additions and 285 deletions
314
gfm/sec8.md
314
gfm/sec8.md
|
@ -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).
|
Its source file name is tfe1.c (text file editor 1).
|
||||||
|
|
||||||
GtkTextView originally has a feature of multi line editing.
|
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.
|
We just add two things to the file viewer.
|
||||||
|
|
||||||
- Static memory is needed to store a pointer to GFile.
|
- Memory to store a pointer to the GFile instance.
|
||||||
- We need to implement file write function.
|
- A function to write the file.
|
||||||
|
|
||||||
A couple of ways are possible to get memories to keep GFile.
|
A couple of ways are possible to get memories to keep GFile.
|
||||||
|
|
||||||
- Use global variables.
|
- 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.
|
Using global variables is easy to implement.
|
||||||
Define a sufficient size array of pointers to GFile.
|
Define a sufficient size array of pointers to GFile.
|
||||||
|
@ -28,13 +28,13 @@ For example,
|
||||||
GFile *f[20];
|
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.
|
However, there are two problems.
|
||||||
One is the size of the array.
|
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.
|
The other is the difficulty of maintenance of the program.
|
||||||
It is a small program so far.
|
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.
|
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.
|
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.
|
A child object includes its parent object.
|
||||||
And a child object derives everything from the 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.
|
We will define TfeTextView as a child object of GtkTextView.
|
||||||
It has everything that GtkTextView has.
|
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.
|
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.
|
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.
|
Let's define TfeTextView object which is a child object of GtkTextView.
|
||||||
First, look at the program below.
|
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.
|
Because knowing the theory is very important for you to program GTK applications.
|
||||||
Look at [GObject API reference](https://developer.gnome.org/gobject/stable/).
|
Look at [GObject API reference](https://developer.gnome.org/gobject/stable/).
|
||||||
All you need is described in it.
|
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.
|
However, it's a tough journey especially for beginners.
|
||||||
For now, you don't need to know such difficult theory.
|
For now, you don't need to know such difficult theory.
|
||||||
Just remember the instructions below.
|
Just remember the instructions below.
|
||||||
|
@ -107,8 +109,8 @@ Tfe and TextView.
|
||||||
Tfe is called prefix, namespace or module.
|
Tfe is called prefix, namespace or module.
|
||||||
TextView is called object.
|
TextView is called object.
|
||||||
- There are three patterns.
|
- 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).
|
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 as tfe\_text\_view\_get\_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.
|
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.
|
And the replacement text is always (prefix)\_(object)\_get\_type () and the letters are lower case.
|
||||||
- Next, use G\_DECLARE\_FINAL\_TYPE macro.
|
- Next, use G\_DECLARE\_FINAL\_TYPE macro.
|
||||||
|
@ -118,31 +120,30 @@ The underscore is necessary.
|
||||||
The first member is the parent object.
|
The first member is the parent object.
|
||||||
Notice this is not a pointer but the object itself.
|
Notice this is not a pointer but the object itself.
|
||||||
The second member and after are members of the child object.
|
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.
|
- 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).
|
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).
|
- Define instance init function (tfe\_text\_view\_init).
|
||||||
Usually you don't need to do anything.
|
Usually you don't need to do anything.
|
||||||
- Define class init function (tfe\_text\_view\_class\_init).
|
- 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).
|
- 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.
|
`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 GFile.
|
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`.
|
`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.
|
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.
|
Its name is (prefix)\_(object)\_new.
|
||||||
If the parent object function needs parameters, this function also need them.
|
If the parent object function needs parameters, this function also need them.
|
||||||
You sometimes might want to add some parameters.
|
You sometimes might want to add some parameters.
|
||||||
It's your choice.
|
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.
|
The arguments are (prefix)\_TYPE\_(object), a list to initialize properties and NULL.
|
||||||
In this code no property needs to be initialized.
|
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.
|
This program is not perfect.
|
||||||
It has some problems.
|
It has some problems.
|
||||||
But I don't discuss them now.
|
|
||||||
It will be modified later.
|
It will be modified later.
|
||||||
|
|
||||||
## Close-request signal
|
## Close-request signal
|
||||||
|
@ -150,7 +151,7 @@ It will be modified later.
|
||||||
Imagine that you use this editor.
|
Imagine that you use this editor.
|
||||||
First, you run the editor with arguments.
|
First, you run the editor with arguments.
|
||||||
The arguments are filenames.
|
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.
|
Then you edit the text.
|
||||||
After you finish editing, you exit the editor.
|
After you finish editing, you exit the editor.
|
||||||
The editor updates files just before the window closes.
|
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.
|
GtkWindow emits "close-request" signal before it closes.
|
||||||
We connect the signal and the handler `before_close`.
|
We connect the signal and the handler `before_close`.
|
||||||
A handler is a C function.
|
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.
|
The function `before_close` is invoked when the signal "close-request" is emitted.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
|
@ -171,46 +172,54 @@ The program of `before_close` is as follows.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
1 static gboolean
|
1 static gboolean
|
||||||
2 before_close (GtkWindow *win, GtkWidget *nb) {
|
2 before_close (GtkWindow *win, gpointer user_data) {
|
||||||
3 GtkWidget *scr;
|
3 GtkWidget *nb = GTK_WIDGET (user_data);
|
||||||
4 GtkWidget *tv;
|
4 GtkWidget *scr;
|
||||||
5 GFile *file;
|
5 GtkWidget *tv;
|
||||||
6 GtkTextBuffer *tb;
|
6 GFile *file;
|
||||||
7 GtkTextIter start_iter;
|
7 char *pathname;
|
||||||
8 GtkTextIter end_iter;
|
8 GtkTextBuffer *tb;
|
||||||
9 char *contents;
|
9 GtkTextIter start_iter;
|
||||||
10 unsigned int n;
|
10 GtkTextIter end_iter;
|
||||||
11 unsigned int i;
|
11 char *contents;
|
||||||
12
|
12 unsigned int n;
|
||||||
13 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
13 unsigned int i;
|
||||||
14 for (i = 0; i < n; ++i) {
|
14
|
||||||
15 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
15 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
||||||
16 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
16 for (i = 0; i < n; ++i) {
|
||||||
17 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
17 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
||||||
18 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
18 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||||
19 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
19 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
||||||
20 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
20 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
21 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
|
21 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||||
22 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
|
22 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||||
23 }
|
23 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) {
|
||||||
24 return FALSE;
|
24 pathname = g_file_get_path (file);
|
||||||
25 }
|
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.
|
The numbers on the left of items are line numbers in the source code.
|
||||||
|
|
||||||
- 13: Gets the number of pages `nb` has.
|
- 15: Gets the number of pages `nb` has.
|
||||||
- 14-23: For loop with regard to the index to each pages.
|
- 16-29: For loop with regard to the index to each pages.
|
||||||
- 15-17: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
|
- 17-19: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
|
||||||
The pointer was stored when `on_open` handler had run. It will be shown later.
|
The pointer was stored when `app_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.
|
- 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.
|
I don't want to explain them now because it would take a lot of time.
|
||||||
Just remember these lines for the present.
|
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
|
## 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
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
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 ---------- */
|
39 /* ---------- end of the definition of TfeTextView ---------- */
|
||||||
40
|
40
|
||||||
41 static gboolean
|
41 static gboolean
|
||||||
42 before_close (GtkWindow *win, GtkWidget *nb) {
|
42 before_close (GtkWindow *win, gpointer user_data) {
|
||||||
43 GtkWidget *scr;
|
43 GtkWidget *nb = GTK_WIDGET (user_data);
|
||||||
44 GtkWidget *tv;
|
44 GtkWidget *scr;
|
||||||
45 GFile *file;
|
45 GtkWidget *tv;
|
||||||
46 GtkTextBuffer *tb;
|
46 GFile *file;
|
||||||
47 GtkTextIter start_iter;
|
47 char *pathname;
|
||||||
48 GtkTextIter end_iter;
|
48 GtkTextBuffer *tb;
|
||||||
49 char *contents;
|
49 GtkTextIter start_iter;
|
||||||
50 unsigned int n;
|
50 GtkTextIter end_iter;
|
||||||
51 unsigned int i;
|
51 char *contents;
|
||||||
52
|
52 unsigned int n;
|
||||||
53 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
53 unsigned int i;
|
||||||
54 for (i = 0; i < n; ++i) {
|
54
|
||||||
55 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
55 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
||||||
56 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
56 for (i = 0; i < n; ++i) {
|
||||||
57 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
57 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
||||||
58 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
58 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||||
59 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
59 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
||||||
60 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
60 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
61 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
|
61 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||||
62 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
|
62 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||||
63 }
|
63 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) {
|
||||||
64 return FALSE;
|
64 pathname = g_file_get_path (file);
|
||||||
65 }
|
65 g_print ("ERROR : Can't save %s.", pathname);
|
||||||
66
|
66 g_free (pathname);
|
||||||
67 static void
|
67 }
|
||||||
68 on_activate (GApplication *app, gpointer user_data) {
|
68 g_free (contents);
|
||||||
69 g_print ("You need to give filenames as arguments.\n");
|
69 }
|
||||||
70 }
|
70 return FALSE;
|
||||||
71
|
71 }
|
||||||
72 static void
|
72
|
||||||
73 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
73 static void
|
||||||
74 GtkWidget *win;
|
74 app_activate (GApplication *app, gpointer user_data) {
|
||||||
75 GtkWidget *nb;
|
75 g_print ("You need to give filenames as arguments.\n");
|
||||||
76 GtkWidget *lab;
|
76 }
|
||||||
77 GtkNotebookPage *nbp;
|
77
|
||||||
78 GtkWidget *scr;
|
78 static void
|
||||||
79 GtkWidget *tv;
|
79 app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||||
80 GtkTextBuffer *tb;
|
80 GtkWidget *win;
|
||||||
81 char *contents;
|
81 GtkWidget *nb;
|
||||||
82 gsize length;
|
82 GtkWidget *lab;
|
||||||
83 char *filename;
|
83 GtkNotebookPage *nbp;
|
||||||
84 int i;
|
84 GtkWidget *scr;
|
||||||
85
|
85 GtkWidget *tv;
|
||||||
86 win = gtk_application_window_new (GTK_APPLICATION (app));
|
86 GtkTextBuffer *tb;
|
||||||
87 gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
87 char *contents;
|
||||||
88 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
88 gsize length;
|
||||||
89 gtk_window_maximize (GTK_WINDOW (win));
|
89 char *filename;
|
||||||
90
|
90 int i;
|
||||||
91 nb = gtk_notebook_new ();
|
91
|
||||||
92 gtk_window_set_child (GTK_WINDOW (win), nb);
|
92 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||||
93
|
93 gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||||
94 for (i = 0; i < n_files; i++) {
|
94 gtk_window_maximize (GTK_WINDOW (win));
|
||||||
95 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
95
|
||||||
96 scr = gtk_scrolled_window_new ();
|
96 nb = gtk_notebook_new ();
|
||||||
97 tv = tfe_text_view_new ();
|
97 gtk_window_set_child (GTK_WINDOW (win), nb);
|
||||||
98 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
98
|
||||||
99 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
99 for (i = 0; i < n_files; i++) {
|
||||||
100 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
100 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||||
101
|
101 scr = gtk_scrolled_window_new ();
|
||||||
102 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
102 tv = tfe_text_view_new ();
|
||||||
103 gtk_text_buffer_set_text (tb, contents, length);
|
103 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
104 g_free (contents);
|
104 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||||
105 filename = g_file_get_basename (files[i]);
|
105 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||||
106 lab = gtk_label_new (filename);
|
106
|
||||||
107 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
107 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||||
108 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
108 gtk_text_buffer_set_text (tb, contents, length);
|
||||||
109 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
109 g_free (contents);
|
||||||
110 g_free (filename);
|
110 filename = g_file_get_basename (files[i]);
|
||||||
111 } else {
|
111 lab = gtk_label_new (filename);
|
||||||
112 filename = g_file_get_path (files[i]);
|
112 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||||
113 g_print ("No such file: %s.\n", filename);
|
113 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
114 g_free (filename);
|
114 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
115 }
|
115 g_free (filename);
|
||||||
116 }
|
116 } else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
117 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
117 g_print ("No such file: %s.\n", filename);
|
||||||
118 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
118 g_free (filename);
|
||||||
119 gtk_widget_show (win);
|
119 } else
|
||||||
120 } else
|
120 g_print ("No valid file is given\n");
|
||||||
121 gtk_window_destroy (GTK_WINDOW (win));
|
121 }
|
||||||
122 }
|
122 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
123
|
123 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
||||||
124 int
|
124 gtk_widget_show (win);
|
||||||
125 main (int argc, char **argv) {
|
125 } else
|
||||||
126 GtkApplication *app;
|
126 gtk_window_destroy (GTK_WINDOW (win));
|
||||||
127 int stat;
|
127 }
|
||||||
128
|
128
|
||||||
129 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
|
129 int
|
||||||
130 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
130 main (int argc, char **argv) {
|
||||||
131 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
131 GtkApplication *app;
|
||||||
132 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
132 int stat;
|
||||||
133 g_object_unref (app);
|
133
|
||||||
134 return stat;
|
134 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
|
||||||
135 }
|
135 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
136
|
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.
|
`files[i]` is a pointer to GFile structure.
|
||||||
It will be freed by the system. So you need to copy it.
|
It will be freed by the system. So you need to copy it.
|
||||||
`g_file_dup` duplicates the given GFile structure.
|
`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.
|
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.
|
So, `nb` is given to `before_close` as the second argument.
|
||||||
|
|
||||||
Now compile and run it.
|
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.
|
Now we got a very simple editor.
|
||||||
It's not smart.
|
It's not smart.
|
||||||
|
|
73
gfm/sec9.md
73
gfm/sec9.md
|
@ -5,7 +5,7 @@ Up: [Readme.md](../Readme.md), Prev: [Section 8](sec8.md), Next: [Section 10](s
|
||||||
## New, open and save button
|
## New, open and save button
|
||||||
|
|
||||||
We made the simplest editor in the previous section.
|
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 works but is not good.
|
||||||
It is better to make "New", "Open", "Save" and "Close" buttons.
|
It is better to make "New", "Open", "Save" and "Close" buttons.
|
||||||
This section describes how to put those buttons into the window.
|
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)
|
![Screenshot of the file editor](../image/screenshot_tfe2.png)
|
||||||
|
|
||||||
The screenshot above shows the layout.
|
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
|
~~~C
|
||||||
1 static void
|
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;
|
3 GtkWidget *win;
|
||||||
4 GtkWidget *nb;
|
4 GtkWidget *nb;
|
||||||
5 GtkWidget *lab;
|
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);
|
73 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
74 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
74 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
75 g_free (filename);
|
75 g_free (filename);
|
||||||
76 } else {
|
76 } else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
77 filename = g_file_get_path (files[i]);
|
77 g_print ("No such file: %s.\n", filename);
|
||||||
78 g_print ("No such file: %s.\n", filename);
|
78 g_free (filename);
|
||||||
79 g_free (filename);
|
79 } else
|
||||||
80 }
|
80 g_print ("No valid file is given\n");
|
||||||
81 }
|
81 }
|
||||||
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
83 gtk_widget_show (win);
|
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.
|
The point is how to build the window.
|
||||||
|
|
||||||
- 25-27: Generates GtkApplicationWindow and sets the title and default size.
|
- 25-27: Creates a GtkApplicationWindow instance and sets the title and default size.
|
||||||
- 29-30: Generates GtkBox `boxv`.
|
- 29-30: Creates a GtkBox instance `boxv`.
|
||||||
It is a vertical box and a child of GtkApplicationWindow.
|
It is a vertical box and a child of GtkApplicationWindow.
|
||||||
It has two children.
|
It has two children.
|
||||||
The first child is a horizontal box includes buttons.
|
The first child is a horizontal box.
|
||||||
The second child is GtkNotebook.
|
The second child is a GtkNotebook.
|
||||||
- 32-33: Generates GtkBox `boxh` and appends it to 'boxv' as a first child.
|
- 32-33: Creates a GtkBox instance `boxh` and appends it to `boxv` as a first child.
|
||||||
- 35-40: Generates three dummy labels.
|
- 35-40: Creates three dummy labels.
|
||||||
The labels `dmy1` and `dmy3` has a character width of ten.
|
The labels `dmy1` and `dmy3` has a character width of ten.
|
||||||
The other label `dmy2` has hexpand property which is set to be TRUE.
|
The other label `dmy2` has hexpand property which is set to be TRUE.
|
||||||
This makes the label expands horizontally as long as possible.
|
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`.
|
- 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.
|
This makes it expand horizontally and vertically as big as possible.
|
||||||
It is appended to `boxv` as the second child.
|
It is appended to `boxv` as the second child.
|
||||||
|
|
||||||
The number of lines is 33(=57-25+1) to build the widgets.
|
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.
|
Most of them aren't necessary except building the widgets.
|
||||||
Are there any good solution to reduce these work?
|
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>
|
59 </interface>
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
This is coded with XML structure.
|
The structure of this file is XML.
|
||||||
Constructs beginning with `<` and ending with `>` are called tags.
|
Constructs beginning with `<` and ending with `>` are called tags.
|
||||||
And there are two types of tags, start tag and end tag.
|
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.
|
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.
|
- 1: The first line is XML declaration.
|
||||||
It specifies that the version of XML is 1.0 and the encoding is UTF-8.
|
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.
|
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.
|
- 3-6: An object with `GtkApplicationWindow` class and `win` id is defined.
|
||||||
This is the top level window.
|
This is the top level window.
|
||||||
And the three properties of the window are defined.
|
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.
|
`title` property is "file editor", `default-width` property is 600 and `default-height` property is 400.
|
||||||
- 7: child tag means a child of the object above.
|
- 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 of `win`.
|
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.
|
Those two describe the same structure of widgets.
|
||||||
|
|
||||||
You can check the ui file with `gtk4-builder-tool`.
|
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.
|
- `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 `--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.
|
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.
|
For example, "TRUE"and "FALSE" becomes "1" and "0" respectively.
|
||||||
However, "TRUE" or "FALSE" is better for maintenance.
|
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.
|
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.
|
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.
|
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.
|
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);
|
> 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.
|
`60,103c61,65` means 44 (=103-60+1) lines are changed to 5 (=65-61+1) lines.
|
||||||
Therefore 37 lines are reduced.
|
Therefore, 39 lines are reduced.
|
||||||
Using ui file not only shortens C source files, but also makes the widgets' structure clear.
|
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
|
~~~C
|
||||||
1 static void
|
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;
|
3 GtkWidget *win;
|
||||||
4 GtkWidget *nb;
|
4 GtkWidget *nb;
|
||||||
5 GtkWidget *lab;
|
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);
|
35 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
36 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
36 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
37 g_free (filename);
|
37 g_free (filename);
|
||||||
38 } else {
|
38 } else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
39 filename = g_file_get_path (files[i]);
|
39 g_print ("No such file: %s.\n", filename);
|
||||||
40 g_print ("No such file: %s.\n", filename);
|
40 g_free (filename);
|
||||||
41 g_free (filename);
|
41 } else
|
||||||
42 }
|
42 g_print ("No valid file is given\n");
|
||||||
43 }
|
43 }
|
||||||
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
45 gtk_widget_show (win);
|
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.
|
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.
|
If you want to see it, click the link above.
|
||||||
You can also get the source files below.
|
|
||||||
|
|
||||||
### Using ui string
|
### Using ui string
|
||||||
|
|
||||||
GtkBuilder can build widgets using 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
|
~~~C
|
||||||
char *uistring;
|
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.
|
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 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
|
### Using Gresource
|
||||||
|
|
||||||
|
|
BIN
image/child.png
BIN
image/child.png
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 21 KiB |
BIN
image/child.xcf
Normal file
BIN
image/child.xcf
Normal file
Binary file not shown.
|
@ -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).
|
Its source file name is tfe1.c (text file editor 1).
|
||||||
|
|
||||||
GtkTextView originally has a feature of multi line editing.
|
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.
|
We just add two things to the file viewer.
|
||||||
|
|
||||||
- Static memory is needed to store a pointer to GFile.
|
- Memory to store a pointer to the GFile instance.
|
||||||
- We need to implement file write function.
|
- A function to write the file.
|
||||||
|
|
||||||
A couple of ways are possible to get memories to keep GFile.
|
A couple of ways are possible to get memories to keep GFile.
|
||||||
|
|
||||||
- Use global variables.
|
- 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.
|
Using global variables is easy to implement.
|
||||||
Define a sufficient size array of pointers to GFile.
|
Define a sufficient size array of pointers to GFile.
|
||||||
|
@ -26,13 +26,13 @@ For example,
|
||||||
GFile *f[20];
|
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.
|
However, there are two problems.
|
||||||
One is the size of the array.
|
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.
|
The other is the difficulty of maintenance of the program.
|
||||||
It is a small program so far.
|
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.
|
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.
|
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.
|
A child object includes its parent object.
|
||||||
And a child object derives everything from the 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.
|
We will define TfeTextView as a child object of GtkTextView.
|
||||||
It has everything that GtkTextView has.
|
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.
|
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.
|
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.
|
Let's define TfeTextView object which is a child object of GtkTextView.
|
||||||
First, look at the program below.
|
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.
|
Because knowing the theory is very important for you to program GTK applications.
|
||||||
Look at [GObject API reference](https://developer.gnome.org/gobject/stable/).
|
Look at [GObject API reference](https://developer.gnome.org/gobject/stable/).
|
||||||
All you need is described in it.
|
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.
|
However, it's a tough journey especially for beginners.
|
||||||
For now, you don't need to know such difficult theory.
|
For now, you don't need to know such difficult theory.
|
||||||
Just remember the instructions below.
|
Just remember the instructions below.
|
||||||
|
@ -105,8 +107,8 @@ Tfe and TextView.
|
||||||
Tfe is called prefix, namespace or module.
|
Tfe is called prefix, namespace or module.
|
||||||
TextView is called object.
|
TextView is called object.
|
||||||
- There are three patterns.
|
- 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).
|
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 as tfe\_text\_view\_get\_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.
|
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.
|
And the replacement text is always (prefix)\_(object)\_get\_type () and the letters are lower case.
|
||||||
- Next, use G\_DECLARE\_FINAL\_TYPE macro.
|
- Next, use G\_DECLARE\_FINAL\_TYPE macro.
|
||||||
|
@ -116,31 +118,30 @@ The underscore is necessary.
|
||||||
The first member is the parent object.
|
The first member is the parent object.
|
||||||
Notice this is not a pointer but the object itself.
|
Notice this is not a pointer but the object itself.
|
||||||
The second member and after are members of the child object.
|
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.
|
- 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).
|
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).
|
- Define instance init function (tfe\_text\_view\_init).
|
||||||
Usually you don't need to do anything.
|
Usually you don't need to do anything.
|
||||||
- Define class init function (tfe\_text\_view\_class\_init).
|
- 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).
|
- 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.
|
`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 GFile.
|
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`.
|
`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.
|
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.
|
Its name is (prefix)\_(object)\_new.
|
||||||
If the parent object function needs parameters, this function also need them.
|
If the parent object function needs parameters, this function also need them.
|
||||||
You sometimes might want to add some parameters.
|
You sometimes might want to add some parameters.
|
||||||
It's your choice.
|
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.
|
The arguments are (prefix)\_TYPE\_(object), a list to initialize properties and NULL.
|
||||||
In this code no property needs to be initialized.
|
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.
|
This program is not perfect.
|
||||||
It has some problems.
|
It has some problems.
|
||||||
But I don't discuss them now.
|
|
||||||
It will be modified later.
|
It will be modified later.
|
||||||
|
|
||||||
## Close-request signal
|
## Close-request signal
|
||||||
|
@ -148,7 +149,7 @@ It will be modified later.
|
||||||
Imagine that you use this editor.
|
Imagine that you use this editor.
|
||||||
First, you run the editor with arguments.
|
First, you run the editor with arguments.
|
||||||
The arguments are filenames.
|
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.
|
Then you edit the text.
|
||||||
After you finish editing, you exit the editor.
|
After you finish editing, you exit the editor.
|
||||||
The editor updates files just before the window closes.
|
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.
|
GtkWindow emits "close-request" signal before it closes.
|
||||||
We connect the signal and the handler `before_close`.
|
We connect the signal and the handler `before_close`.
|
||||||
A handler is a C function.
|
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.
|
The function `before_close` is invoked when the signal "close-request" is emitted.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
|
@ -173,33 +174,38 @@ tfe/tfe1.c before_close
|
||||||
|
|
||||||
The numbers on the left of items are line numbers in the source code.
|
The numbers on the left of items are line numbers in the source code.
|
||||||
|
|
||||||
- 13: Gets the number of pages `nb` has.
|
- 15: Gets the number of pages `nb` has.
|
||||||
- 14-23: For loop with regard to the index to each pages.
|
- 16-29: For loop with regard to the index to each pages.
|
||||||
- 15-17: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
|
- 17-19: Gets GtkScrolledWindow, TfeTextView and a pointer to GFile.
|
||||||
The pointer was stored when `on_open` handler had run. It will be shown later.
|
The pointer was stored when `app_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.
|
- 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.
|
I don't want to explain them now because it would take a lot of time.
|
||||||
Just remember these lines for the present.
|
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
|
## 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
|
@@@include
|
||||||
tfe/tfe1.c
|
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.
|
`files[i]` is a pointer to GFile structure.
|
||||||
It will be freed by the system. So you need to copy it.
|
It will be freed by the system. So you need to copy it.
|
||||||
`g_file_dup` duplicates the given GFile structure.
|
`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.
|
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.
|
So, `nb` is given to `before_close` as the second argument.
|
||||||
|
|
||||||
Now compile and run it.
|
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.
|
Now we got a very simple editor.
|
||||||
It's not smart.
|
It's not smart.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
## New, open and save button
|
## New, open and save button
|
||||||
|
|
||||||
We made the simplest editor in the previous section.
|
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 works but is not good.
|
||||||
It is better to make "New", "Open", "Save" and "Close" buttons.
|
It is better to make "New", "Open", "Save" and "Close" buttons.
|
||||||
This section describes how to put those buttons into the window.
|
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}
|
![Screenshot of the file editor](../image/screenshot_tfe2.png){width=9.3cm height=6.825cm}
|
||||||
|
|
||||||
The screenshot above shows the layout.
|
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
|
@@@include
|
||||||
tfe/tfe2.c on_open
|
tfe/tfe2.c app_open
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
The point is how to build the window.
|
The point is how to build the window.
|
||||||
|
|
||||||
- 25-27: Generates GtkApplicationWindow and sets the title and default size.
|
- 25-27: Creates a GtkApplicationWindow instance and sets the title and default size.
|
||||||
- 29-30: Generates GtkBox `boxv`.
|
- 29-30: Creates a GtkBox instance `boxv`.
|
||||||
It is a vertical box and a child of GtkApplicationWindow.
|
It is a vertical box and a child of GtkApplicationWindow.
|
||||||
It has two children.
|
It has two children.
|
||||||
The first child is a horizontal box includes buttons.
|
The first child is a horizontal box.
|
||||||
The second child is GtkNotebook.
|
The second child is a GtkNotebook.
|
||||||
- 32-33: Generates GtkBox `boxh` and appends it to 'boxv' as a first child.
|
- 32-33: Creates a GtkBox instance `boxh` and appends it to `boxv` as a first child.
|
||||||
- 35-40: Generates three dummy labels.
|
- 35-40: Creates three dummy labels.
|
||||||
The labels `dmy1` and `dmy3` has a character width of ten.
|
The labels `dmy1` and `dmy3` has a character width of ten.
|
||||||
The other label `dmy2` has hexpand property which is set to be TRUE.
|
The other label `dmy2` has hexpand property which is set to be TRUE.
|
||||||
This makes the label expands horizontally as long as possible.
|
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`.
|
- 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.
|
This makes it expand horizontally and vertically as big as possible.
|
||||||
It is appended to `boxv` as the second child.
|
It is appended to `boxv` as the second child.
|
||||||
|
|
||||||
The number of lines is 33(=57-25+1) to build the widgets.
|
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.
|
Most of them aren't necessary except building the widgets.
|
||||||
Are there any good solution to reduce these work?
|
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
|
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.
|
Constructs beginning with `<` and ending with `>` are called tags.
|
||||||
And there are two types of tags, start tag and end tag.
|
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.
|
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.
|
- 1: The first line is XML declaration.
|
||||||
It specifies that the version of XML is 1.0 and the encoding is UTF-8.
|
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.
|
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.
|
- 3-6: An object with `GtkApplicationWindow` class and `win` id is defined.
|
||||||
This is the top level window.
|
This is the top level window.
|
||||||
And the three properties of the window are defined.
|
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.
|
`title` property is "file editor", `default-width` property is 600 and `default-height` property is 400.
|
||||||
- 7: child tag means a child of the object above.
|
- 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 of `win`.
|
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.
|
Those two describe the same structure of widgets.
|
||||||
|
|
||||||
You can check the ui file with `gtk4-builder-tool`.
|
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.
|
- `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 `--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.
|
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.
|
For example, "TRUE"and "FALSE" becomes "1" and "0" respectively.
|
||||||
However, "TRUE" or "FALSE" is better for maintenance.
|
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.
|
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.
|
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.
|
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.
|
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
|
cd tfe; diff tfe2.c tfe3.c
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
`60,103c61,65` means 42 (=103-60+1) lines change to 5 (=65-61+1) lines.
|
`60,103c61,65` means 44 (=103-60+1) lines are changed to 5 (=65-61+1) lines.
|
||||||
Therefore 37 lines are reduced.
|
Therefore, 39 lines are reduced.
|
||||||
Using ui file not only shortens C source files, but also makes the widgets' structure clear.
|
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
|
@@@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.
|
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.
|
If you want to see it, click the link above.
|
||||||
You can also get the source files below.
|
|
||||||
|
|
||||||
### Using ui string
|
### Using ui string
|
||||||
|
|
||||||
GtkBuilder can build widgets using 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
|
~~~C
|
||||||
char *uistring;
|
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.
|
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 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
|
### Using Gresource
|
||||||
|
|
||||||
|
|
4
src/tfe/taketori.txt
Normal file
4
src/tfe/taketori.txt
Normal 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.
|
||||||
|
|
|
@ -39,10 +39,12 @@ tfe_text_view_new (void) {
|
||||||
/* ---------- end of the definition of TfeTextView ---------- */
|
/* ---------- end of the definition of TfeTextView ---------- */
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
before_close (GtkWindow *win, GtkWidget *nb) {
|
before_close (GtkWindow *win, gpointer user_data) {
|
||||||
|
GtkWidget *nb = GTK_WIDGET (user_data);
|
||||||
GtkWidget *scr;
|
GtkWidget *scr;
|
||||||
GtkWidget *tv;
|
GtkWidget *tv;
|
||||||
GFile *file;
|
GFile *file;
|
||||||
|
char *pathname;
|
||||||
GtkTextBuffer *tb;
|
GtkTextBuffer *tb;
|
||||||
GtkTextIter start_iter;
|
GtkTextIter start_iter;
|
||||||
GtkTextIter end_iter;
|
GtkTextIter end_iter;
|
||||||
|
@ -58,19 +60,23 @@ before_close (GtkWindow *win, GtkWidget *nb) {
|
||||||
tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||||
contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
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))
|
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));
|
pathname = g_file_get_path (file);
|
||||||
|
g_print ("ERROR : Can't save %s.", pathname);
|
||||||
|
g_free (pathname);
|
||||||
|
}
|
||||||
|
g_free (contents);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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");
|
g_print ("You need to give filenames as arguments.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 *win;
|
||||||
GtkWidget *nb;
|
GtkWidget *nb;
|
||||||
GtkWidget *lab;
|
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));
|
win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||||
gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
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));
|
gtk_window_maximize (GTK_WINDOW (win));
|
||||||
|
|
||||||
nb = gtk_notebook_new ();
|
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);
|
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
g_free (filename);
|
g_free (filename);
|
||||||
} else {
|
} else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
filename = g_file_get_path (files[i]);
|
g_print ("No such file: %s.\n", filename);
|
||||||
g_print ("No such file: %s.\n", filename);
|
g_free (filename);
|
||||||
g_free (filename);
|
} else
|
||||||
}
|
g_print ("No valid file is given\n");
|
||||||
}
|
}
|
||||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
||||||
|
@ -127,10 +132,9 @@ main (int argc, char **argv) {
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
|
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, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,12 +39,12 @@ tfe_text_view_new (void) {
|
||||||
/* ---------- end of the definition of TfeTextView ---------- */
|
/* ---------- end of the definition of TfeTextView ---------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_activate (GApplication *app, gpointer user_data) {
|
app_activate (GApplication *app, gpointer user_data) {
|
||||||
g_print ("You need a filename argument.\n");
|
g_print ("You need a filename argument.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 *win;
|
||||||
GtkWidget *nb;
|
GtkWidget *nb;
|
||||||
GtkWidget *lab;
|
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);
|
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
g_free (filename);
|
g_free (filename);
|
||||||
} else {
|
} else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
filename = g_file_get_path (files[i]);
|
g_print ("No such file: %s.\n", filename);
|
||||||
g_print ("No such file: %s.\n", filename);
|
g_free (filename);
|
||||||
g_free (filename);
|
} else
|
||||||
}
|
g_print ("No valid file is given\n");
|
||||||
}
|
}
|
||||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
gtk_widget_show (win);
|
gtk_widget_show (win);
|
||||||
|
@ -136,8 +136,8 @@ main (int argc, char **argv) {
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfe2", G_APPLICATION_HANDLES_OPEN);
|
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, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
return stat;
|
return stat;
|
||||||
|
|
|
@ -39,12 +39,12 @@ tfe_text_view_new (void) {
|
||||||
/* ---------- end of the definition of TfeTextView ---------- */
|
/* ---------- end of the definition of TfeTextView ---------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_activate (GApplication *app, gpointer user_data) {
|
app_activate (GApplication *app, gpointer user_data) {
|
||||||
g_print ("You need a filename argument.\n");
|
g_print ("You need a filename argument.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 *win;
|
||||||
GtkWidget *nb;
|
GtkWidget *nb;
|
||||||
GtkWidget *lab;
|
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);
|
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
g_free (filename);
|
g_free (filename);
|
||||||
} else {
|
} else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
filename = g_file_get_path (files[i]);
|
g_print ("No such file: %s.\n", filename);
|
||||||
g_print ("No such file: %s.\n", filename);
|
g_free (filename);
|
||||||
g_free (filename);
|
} else
|
||||||
}
|
g_print ("No valid file is given\n");
|
||||||
}
|
}
|
||||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
gtk_widget_show (win);
|
gtk_widget_show (win);
|
||||||
|
@ -98,8 +98,8 @@ main (int argc, char **argv) {
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
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, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
return stat;
|
return stat;
|
||||||
|
|
|
@ -39,12 +39,12 @@ tfe_text_view_new (void) {
|
||||||
/* ---------- end of the definition of TfeTextView ---------- */
|
/* ---------- end of the definition of TfeTextView ---------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_activate (GApplication *app, gpointer user_data) {
|
app_activate (GApplication *app, gpointer user_data) {
|
||||||
g_print ("You need a filename argument.\n");
|
g_print ("You need a filename argument.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 *win;
|
||||||
GtkWidget *nb;
|
GtkWidget *nb;
|
||||||
GtkWidget *lab;
|
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);
|
nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||||
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||||
g_free (filename);
|
g_free (filename);
|
||||||
} else {
|
} else if ((filename = g_file_get_path (files[i])) != NULL) {
|
||||||
filename = g_file_get_path (files[i]);
|
g_print ("No such file: %s.\n", filename);
|
||||||
g_print ("No such file: %s.\n", filename);
|
g_free (filename);
|
||||||
g_free (filename);
|
} else
|
||||||
}
|
g_print ("No valid file is given\n");
|
||||||
}
|
}
|
||||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||||
gtk_widget_show (win);
|
gtk_widget_show (win);
|
||||||
|
@ -98,8 +98,8 @@ main (int argc, char **argv) {
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
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, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
return stat;
|
return stat;
|
||||||
|
|
Loading…
Reference in a new issue