mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
Merge pull request #19 from PaulSchulz/main
Some more changes for readabilty.
This commit is contained in:
commit
1d4741bdb9
9 changed files with 332 additions and 314 deletions
44
gfm/sec5.md
44
gfm/sec5.md
|
@ -21,16 +21,16 @@ See the sample program `tfv1.c` below.
|
|||
8 gchar *text;
|
||||
9
|
||||
10 text =
|
||||
11 "Once upon a time, there was an old man who was called Taketori-no-Okina. "
|
||||
12 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
13 "One day, he went into a mountain and found a shining bamboo. "
|
||||
14 "\"What a mysterious bamboo it is!,\" he said. "
|
||||
15 "He cut it, then there was a small cute baby girl in it. "
|
||||
16 "The girl was shining faintly. "
|
||||
17 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
18 "His wife was surprized at his tale. "
|
||||
19 "They were very happy because they had no children. "
|
||||
20 ;
|
||||
11 "Once upon a time, there was an old man who was called Taketori-no-Okina. "
|
||||
12 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
13 "One day, he went into a mountain and found a shining bamboo. "
|
||||
14 "\"What a mysterious bamboo it is!,\" he said. "
|
||||
15 "He cut it, then there was a small cute baby girl in it. "
|
||||
16 "The girl was shining faintly. "
|
||||
17 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
18 "His wife was surprized at his tale. "
|
||||
19 "They were very happy because they had no children. "
|
||||
20 ;
|
||||
21 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
22 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
23 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
|
@ -52,7 +52,7 @@ See the sample program `tfv1.c` below.
|
|||
39
|
||||
40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||
41 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
42 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
42 stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
43 g_object_unref (app);
|
||||
44 return stat;
|
||||
45 }
|
||||
|
@ -125,16 +125,16 @@ Here is the complete code of `tfv2.c`.
|
|||
9 gchar *text;
|
||||
10
|
||||
11 text =
|
||||
12 "Once upon a time, there was an old man who was called Taketori-no-Okina. "
|
||||
13 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
14 "One day, he went into a mountain and found a shining bamboo. "
|
||||
15 "\"What a mysterious bamboo it is!,\" he said. "
|
||||
16 "He cut it, then there was a small cute baby girl in it. "
|
||||
17 "The girl was shining faintly. "
|
||||
18 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
19 "His wife was surprized at his tale. "
|
||||
20 "They were very happy because they had no children. "
|
||||
21 ;
|
||||
12 "Once upon a time, there was an old man who was called Taketori-no-Okina. "
|
||||
13 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
14 "One day, he went into a mountain and found a shining bamboo. "
|
||||
15 "\"What a mysterious bamboo it is!,\" he said. "
|
||||
16 "He cut it, then there was a small cute baby girl in it. "
|
||||
17 "The girl was shining faintly. "
|
||||
18 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
19 "His wife was surprized at his tale. "
|
||||
20 "They were very happy because they had no children. "
|
||||
21 ;
|
||||
22 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
23 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
|
@ -159,7 +159,7 @@ Here is the complete code of `tfv2.c`.
|
|||
43
|
||||
44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||
45 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
46 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
46 stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
47 g_object_unref (app);
|
||||
48 return stat;
|
||||
49 }
|
||||
|
|
119
gfm/sec6.md
119
gfm/sec6.md
|
@ -2,15 +2,18 @@ Up: [Readme.md](../Readme.md), Prev: [Section 5](sec5.md), Next: [Section 7](se
|
|||
|
||||
# String and memory management
|
||||
|
||||
GtkTextView and GtkTextBuffer have functions that have string parameters or return a string.
|
||||
The knowledge of strings and memory management is very important for us to understand the functions above.
|
||||
GtkTextView and GtkTextBuffer have functions that use string parameters or return a string.
|
||||
The knowledge of strings and memory management is useful to understand how to use these functions.
|
||||
|
||||
## String and memory
|
||||
|
||||
String is an array of characters that is terminated with '\0'.
|
||||
String is not a C type such as char, int, float or double.
|
||||
But the pointer to a character array behaves like a string type of other languages.
|
||||
So, the pointer is often called string.
|
||||
A String is an array of characters that is terminated with '\0'.
|
||||
Strings are not a C type such as char, int, float or double,
|
||||
but exist as a pointer to a character array. They behaves like a string type
|
||||
which you may be familiar from other languages.
|
||||
So, this pointer is often called 'a string'.
|
||||
|
||||
In the following, `a` and `b` defined as character arrays, and are strings.
|
||||
|
||||
~~~C
|
||||
char a[10], *b;
|
||||
|
@ -27,46 +30,50 @@ b = a;
|
|||
/* *(++b) is 'e' */
|
||||
~~~
|
||||
|
||||
The array `a` has `char` elements and the size is ten.
|
||||
The array `a` has `char` elements and the size of ten.
|
||||
The first six elements are 'H', 'e', 'l', 'l', 'o' and '\0'.
|
||||
This array represents a string "Hello".
|
||||
This array represents the string "Hello".
|
||||
The first five elements are character codes that correspond to the characters.
|
||||
The sixth element is '\0' that is the same as zero.
|
||||
And it indicates that the string ends there.
|
||||
The size of the array is 10, so 4 bytes aren't used, but it's OK.
|
||||
They are just ignored.
|
||||
The sixth element is '\0', which is the same as zero,
|
||||
and indicates that the string ends there.
|
||||
The size of the array is 10, so 4 bytes aren't used, but that's OK,
|
||||
they are just ignored.
|
||||
|
||||
The variable 'b' is a pointer to a character.
|
||||
Because `a` is assigned to `b`, `a` and `b` point the same character ('H').
|
||||
Because `b` is assigned to be `a`, `a` and `b` point the same character ('H').
|
||||
The variable `a` is defined as an array and it can't be changed.
|
||||
It always point the top address of the array.
|
||||
On the other hand, pointers are mutable, so `b` can change itself.
|
||||
It is possible to write `++b` (`b` is increased by one).
|
||||
On the other hand, 'b' is a pointer, which is mutable, so `b` can be change.
|
||||
It is then possible to write statements like `++b`, which means take the value in b (n address),
|
||||
increase it by one, and store that back in `b`.
|
||||
|
||||
If a pointer is NULL, it points nothing.
|
||||
If a pointer is NULL, it points to nothing.
|
||||
So, the pointer is not a string.
|
||||
Programs with string will include bugs if you aren't careful about NULL pointer.
|
||||
A NULL string on the other hand will be a pointer which points to a location
|
||||
that contains `\0`, which is a string of length 0 (or "").
|
||||
Programs that use strings will include bugs if you aren't careful when using NULL pointers.
|
||||
|
||||
Another annoying problem is memory that a string is allocated.
|
||||
There are four cases.
|
||||
Another annoying problem is the memory that a string is allocated.
|
||||
There are four cases:
|
||||
|
||||
- The string is read only.
|
||||
- The string is in static memory area.
|
||||
- The string is in stack.
|
||||
- The string is read only;
|
||||
- The string is in static memory area;
|
||||
- The string is in stack; and
|
||||
- The string is in memory allocated from the heap area.
|
||||
|
||||
## Read only string
|
||||
|
||||
A string literal in C program is surrounded by double quotes.
|
||||
A string literal in a C program is surrounded by double quotes and written as the following:
|
||||
|
||||
~~~C
|
||||
char *s;
|
||||
s = "Hello"
|
||||
~~~
|
||||
|
||||
"Hello" is a string literal.
|
||||
"Hello" is a string literal, and is stored in program memory.
|
||||
A string literal is read only.
|
||||
In the program above, `s` points the string literal.
|
||||
|
||||
So, the following program is illegal.
|
||||
|
||||
~~~C
|
||||
|
@ -76,18 +83,22 @@ So, the following program is illegal.
|
|||
The result is undefined.
|
||||
Probably a bad thing will happen, for example, a segmentation fault.
|
||||
|
||||
NOTE: The memory of the literal string is allocated when the program is
|
||||
compiled. It is possible to view all the literal strings defined in your program
|
||||
by using the `string` command.
|
||||
|
||||
## Strings defined as arrays
|
||||
|
||||
If a string is defined as an array, it's in static memory area or stack.
|
||||
It depends on the class of the array.
|
||||
If a string is defined as an array, it's in either stored in the static memory area or stack.
|
||||
This depends on the class of the array.
|
||||
If the array's class is `static`, then it's placed in static memory area.
|
||||
It keeps its value and remains for the life of the program.
|
||||
This area is writable.
|
||||
This allocation and memory address is fixed for the life of the program.
|
||||
This area can be changed and is writable.
|
||||
|
||||
If the array's class is `auto`, then it's placed in stack.
|
||||
If the array is defined in a function, its default class is `auto`.
|
||||
The stack area will disappear when the function returns to the caller.
|
||||
stack is writable.
|
||||
If the array is defined inside a function, its default class is `auto`.
|
||||
The stack area will disappear when the function exits and returns to the caller.
|
||||
Arrays defined on the stack are writable.
|
||||
|
||||
~~~C
|
||||
|
||||
|
@ -105,30 +116,30 @@ print_strings (void) {
|
|||
}
|
||||
~~~
|
||||
|
||||
The array `a` is defined externally to functions.
|
||||
The array `a` is defined externally to a function and is global in its scope.
|
||||
Such variables are placed in static memory area even if the `static` class is left out.
|
||||
First, the compiler calculates the number of the elements in the right hand side.
|
||||
It is six.
|
||||
The compiler allocates six bytes memory in the static memory area and copies the data to the memory.
|
||||
The compiler calculates the number of the elements in the right hand side (six),
|
||||
and then creates code that allocates six bytes in the static memory area and copies the data to this memory.
|
||||
|
||||
The array `b` is defined inside the function.
|
||||
So, its class is `auto`.
|
||||
The array `b` is defined inside the function
|
||||
so its class is `auto`.
|
||||
The compiler calculates the number of the elements in the string literal.
|
||||
It is six because the string is zero terminated.
|
||||
The compiler allocates six bytes memory in the stack and copies the data to the memory.
|
||||
It has six elements as the zero termination character is also included.
|
||||
The compiler creates code which allocates six bytes memory in the stack and copies the data to the memory.
|
||||
|
||||
Both `a` and `b` are writable.
|
||||
|
||||
The memory is managed by the executable program.
|
||||
You don't need to program to allocate or free the memory for `a` and `b`.
|
||||
The array `a` remains for the life of the program.
|
||||
The array `b` disappears when the function returns to the caller.
|
||||
You don't need your program to allocate or free the memory for `a` and `b`.
|
||||
The array `a` is created then the program is first run and remains for the life of the program.
|
||||
The array `b` is created on the stack then the function is called, disappears when the function returns.
|
||||
|
||||
## Strings in the heap area
|
||||
|
||||
You can get memory from the heap area and put back the memory to the heap area.
|
||||
You can also get, use and release memory from the heap area.
|
||||
The standard C library provides `malloc` to get memory and `free` to put back memory.
|
||||
Similarly, GLib provides `g_new` and `g_free`.
|
||||
GLib provides the functions `g_new` and `g_free` to do the same thing, with support for
|
||||
some additional Glib functionality.
|
||||
|
||||
~~~C
|
||||
g_new (struct_type, n_struct)
|
||||
|
@ -165,7 +176,7 @@ If `mem` is NULL, `g_free` does nothing.
|
|||
`gpointer` is a type of general pointer.
|
||||
It is the same as `void *`.
|
||||
This pointer can be casted to any pointer type.
|
||||
Conversely, any pointer type can be casted to gpointer.
|
||||
Conversely, any pointer type can be casted to `gpointer`.
|
||||
|
||||
~~~C
|
||||
g_free (s);
|
||||
|
@ -175,10 +186,10 @@ g_free (t);
|
|||
/* Frees the memory allocated to t. */
|
||||
~~~
|
||||
|
||||
If the argument doesn't point allocated memory, it will cause an error, for example, segmentation fault.
|
||||
If the argument doesn't point allocated memory it will cause an error, specifically, a segmentation fault.
|
||||
|
||||
Some Glib functions allocate memory.
|
||||
For example, `g_strdup` allocates memory and copy a string given as an argument.
|
||||
For example, `g_strdup` allocates memory and copies a string given as an argument.
|
||||
|
||||
~~~C
|
||||
char *s;
|
||||
|
@ -196,8 +207,11 @@ The following is extracted from the reference.
|
|||
|
||||
> The returned string should be freed with `g_free()` when no longer needed.
|
||||
|
||||
The reference usually describes if the returned value needs to be freed.
|
||||
If you forget to free the allocated memory, it causes memory leak.
|
||||
The function reference will describe if the returned value needs to be freed.
|
||||
If you forget to free the allocated memory it will remain allocated. Repeated use will cause
|
||||
more memory to be allocated to the program, which will grow over time. This is called a memory leak,
|
||||
and the only way to address this bug is to close the program (and restart it),
|
||||
which will automatically release all of the programs memory back to the system.
|
||||
|
||||
Some GLib functions return a string which mustn't be freed by the caller.
|
||||
|
||||
|
@ -207,10 +221,10 @@ g_quark_to_string (GQuark quark);
|
|||
~~~
|
||||
|
||||
This function returns `const char*` type.
|
||||
The qualifier `const` means immutable.
|
||||
Therefore, the characters pointed by the returned value aren't be allowed to change or free.
|
||||
The qualifier `const` means that the returned value is immutable.
|
||||
The characters pointed by the returned value aren't be allowed to be changed or freed.
|
||||
|
||||
If a variable is qualified with `const`, the variable can't be assigned except initialization.
|
||||
If a variable is qualified with `const`, the variable can't be assigned except during initialization.
|
||||
|
||||
~~~C
|
||||
const int x = 10; /* initialization is OK. */
|
||||
|
@ -218,5 +232,4 @@ const int x = 10; /* initialization is OK. */
|
|||
x = 20; /* This is illegal because x is qualified with const */
|
||||
~~~
|
||||
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 5](sec5.md), Next: [Section 7](sec7.md)
|
||||
|
|
160
gfm/sec7.md
160
gfm/sec7.md
|
@ -6,21 +6,22 @@ Up: [Readme.md](../Readme.md), Prev: [Section 6](sec6.md), Next: [Section 8](se
|
|||
|
||||
### G\_APPLICATION\_HANDLES\_OPEN flag
|
||||
|
||||
GtkTextView, GtkTextBuffer and GtkScrolledWindow have given us a minimum editor in the previous section.
|
||||
Next, we will add a function to read a file and remake the program into a file viewer.
|
||||
There are many ways to implement the function.
|
||||
Because this is a tutorial for beginners, we'll take the easiest one.
|
||||
The GtkTextView, GtkTextBuffer and GtkScrolledWindow widgets have given us a minimum editor
|
||||
in the previous section.
|
||||
We will now add a function to read a file and rework the program into a file viewer.
|
||||
There are many ways to implement the function and
|
||||
because this is a tutorial for beginners, we'll take the easiest one.
|
||||
|
||||
When the program starts, we give a filename as an argument.
|
||||
When the program starts, we will give the filename to open as an argument.
|
||||
|
||||
$ ./a.out filename
|
||||
|
||||
Then it opens the file and inserts its contents into the GtkTextBuffer.
|
||||
It will open the file and insert its contents into the GtkTextBuffer.
|
||||
|
||||
At the beginning of the implementation, we need to know how GtkApplication (or GApplication) recognizes arguments.
|
||||
It is described in the [GIO API Reference, Application](https://docs.gtk.org/gio/class.Application.html).
|
||||
To do this, we need to know how GtkApplication (or GApplication) recognizes arguments.
|
||||
This is described in the [GIO API Reference, Application](https://docs.gtk.org/gio/class.Application.html).
|
||||
|
||||
When GtkApplication is created, a flag (its type is GApplicationFlags) is given as an argument.
|
||||
When GtkApplication is created, a flag (with the type GApplicationFlags) is provided as an argument.
|
||||
|
||||
~~~C
|
||||
GtkApplication *
|
||||
|
@ -28,9 +29,9 @@ gtk_application_new (const gchar *application_id, GApplicationFlags flags);
|
|||
~~~
|
||||
|
||||
This tutorial explains only two flags, `G_APPLICATION_FLAGS_NONE` and `G_APPLICATION_HANDLES_OPEN`.
|
||||
If you want to handle command line arguments, `G_APPLICATION_HANDLES_COMMAND_LINE` flag is what you need.
|
||||
How to program it is written in [GIO API Reference, g\_application\_run](https://docs.gtk.org/gio/method.Application.run.html).
|
||||
And the flag is described in the [GIO API Reference, ApplicationFlags](https://docs.gtk.org/gio/flags.ApplicationFlags.html).
|
||||
If you want to handle command line arguments, the `G_APPLICATION_HANDLES_COMMAND_LINE` flag is what you need.
|
||||
How to use the new application method is described in [GIO API Reference, g\_application\_run](https://docs.gtk.org/gio/method.Application.run.html),
|
||||
and the flag is described in the [GIO API Reference, ApplicationFlags](https://docs.gtk.org/gio/flags.ApplicationFlags.html).
|
||||
|
||||
~~~
|
||||
GApplicationFlags' Members
|
||||
|
@ -41,18 +42,15 @@ G_APPLICATION_HANDLES_OPEN This application handles opening files (in the prima
|
|||
... ... ...
|
||||
~~~
|
||||
|
||||
There are ten flags.
|
||||
But we only need two of them so far.
|
||||
We've already used `G_APPLICATION_FLAGS_NONE`.
|
||||
It is the simplest option.
|
||||
No argument is allowed.
|
||||
If you give arguments and run the application, then error occurs.
|
||||
There are ten flags in total, but we only need two of them so far.
|
||||
We've already used `G_APPLICATION_FLAGS_NONE`, as
|
||||
it is the simplest option, and no arguments are allowed.
|
||||
If you provide arguments when running the application, an error will occur.
|
||||
|
||||
`G_APPLICATION_HANDLES_OPEN` is the second simplest option.
|
||||
The flag `G_APPLICATION_HANDLES_OPEN` is the second simplest option.
|
||||
It allows arguments but only files.
|
||||
The application assumes all the arguments are filenames.
|
||||
|
||||
Now we use this flag when creating GtkApplication.
|
||||
The application assumes all the arguments are filenames and we will use this flag when creating
|
||||
our GtkApplication.
|
||||
|
||||
~~~C
|
||||
app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||
|
@ -60,12 +58,12 @@ app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPE
|
|||
|
||||
### open signal
|
||||
|
||||
When the application starts, two signals are possible.
|
||||
Now, when the application starts, two signals can be emitted.
|
||||
|
||||
- activate signal --- This signal is emitted when there's no argument.
|
||||
- open signal --- This signal is emitted when there is at least one argument.
|
||||
|
||||
The handler of "open" signal is defined as follows.
|
||||
The handler of the "open" signal is defined as follows.
|
||||
|
||||
~~~C
|
||||
void user_function (GApplication *application,
|
||||
|
@ -83,22 +81,22 @@ The parameters are:
|
|||
- `hint` --- a hint provided by the calling instance (usually it can be ignored)
|
||||
- `user_data` --- user data set when the signal handler was connected.
|
||||
|
||||
The way how to read a file (GFile) will be described in the next subsection.
|
||||
How to read a specified file (GFile) will be described next.
|
||||
|
||||
## Making a file viewer
|
||||
|
||||
### What is a file viewer?
|
||||
|
||||
A file viewer is a program that shows a text file given as an argument.
|
||||
It works as follows.
|
||||
A file viewer is a program that displays the text file that is given as an argument.
|
||||
Our file viewer will work as follows.
|
||||
|
||||
- If it is given arguments, it recognizes the first argument as a filename and opens it.
|
||||
- If opening the file succeeds, it reads the contents of the file and inserts it to GtkTextBuffer and shows the window.
|
||||
- If it fails to open the file, shows an error message and quits.
|
||||
- If there's no argument, it shows an error message and quits.
|
||||
- If there are two or more arguments, the second one and after are ignored.
|
||||
- When arguments are given, it treats the first argument as a filename and opens it.
|
||||
- If opening the file succeeds, it reads the contents of the file and inserts it to GtkTextBuffer and then shows the window.
|
||||
- If it fails to open the file, it will show an error message and quit.
|
||||
- If there's no argument, it will shows an error message and quit.
|
||||
- If there are two or more arguments, the second one and any others are ignored.
|
||||
|
||||
The program is as follows.
|
||||
The program which does this is shown below.
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
|
@ -155,11 +153,10 @@ The program is as follows.
|
|||
52 app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||
53 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
54 g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||
55 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
55 stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
56 g_object_unref (app);
|
||||
57 return stat;
|
||||
58 }
|
||||
59
|
||||
~~~
|
||||
|
||||
Save it as `tfv3.c`.
|
||||
|
@ -170,25 +167,25 @@ Then compile and run it.
|
|||
|
||||
![File viewer](../image/screenshot_tfv3.png)
|
||||
|
||||
Now I want to explain the program `tfv3.c`.
|
||||
First, the function `main` changes in only two lines from the previous version.
|
||||
Let's explain how the program `tfv3.c` works.
|
||||
First, the function `main` has only two changes from the previous version.
|
||||
|
||||
- `G_APPLICATION_FLAGS_NONE` is replaced by `G_APPLICATION_HANDLES_OPEN`.
|
||||
- `G_APPLICATION_FLAGS_NONE` is replaced by `G_APPLICATION_HANDLES_OPEN`; and
|
||||
- `g_signal_connect (app, "open", G_CALLBACK (on_open), NULL)` is added.
|
||||
|
||||
Next, the handler `app_activate` is now very simple.
|
||||
It just outputs the error message.
|
||||
The application quits immediately because no window is created.
|
||||
Next, the handler `app_activate` is added and is very simple.
|
||||
It just outputs the error message and
|
||||
the application quits immediately because no window is created.
|
||||
|
||||
The point is the handler `app_open`.
|
||||
The main functionality is the in the handler `app_open`. It
|
||||
|
||||
- It creates GtkApplicationWindow, GtkScrolledWindow, GtkTextView and GtkTextBuffer and connects them.
|
||||
- Sets wrap mode to `GTK_WRAP_WORD_CHAR` in GtktextView.
|
||||
- Sets GtkTextView to non-editable because the program isn't an editor but only a viewer.
|
||||
- Reads the file and inserts the text into GtkTextBuffer (this will be explained in detail later).
|
||||
- If the file is not opened then outputs an error message and destroys the window. It makes the application quit.
|
||||
- Creates GtkApplicationWindow, GtkScrolledWindow, GtkTextView and GtkTextBuffer and connects them together;
|
||||
- Sets wrap mode to `GTK_WRAP_WORD_CHAR` in GtktextView;
|
||||
- Sets GtkTextView to non-editable because the program isn't an editor but only a viewer;
|
||||
- Reads the file and inserts the text into GtkTextBuffer (this will be explained in detail later); and
|
||||
- If the file is not opened then outputs an error message and destroys the window. This makes the application quit.
|
||||
|
||||
The file reading part of the program is shown again below.
|
||||
The following is the important file reading part of the program and is shown again below.
|
||||
|
||||
~~~C
|
||||
if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
||||
|
@ -208,29 +205,32 @@ if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
|||
}
|
||||
~~~
|
||||
|
||||
The function `g_file_load_contents` loads the file contents into a buffer, which is automatically allocated, and sets `contents` to point the buffer.
|
||||
And the length of the buffer is set to `length`.
|
||||
It returns `TRUE` if the file's contents are successfully loaded. `FALSE` if an error happens.
|
||||
The function `g_file_load_contents` loads the file contents into a buffer,
|
||||
which is automatically allocated and sets `contents` to point that buffer.
|
||||
The length of the buffer is set to `length`.
|
||||
It returns `TRUE` if the file's contents are successfully loaded and `FALSE` if an error occurs.
|
||||
|
||||
If the function succeeds, it inserts the contents into GtkTextBuffer, frees the buffer memories pointed by `contents`, sets the title of the window,
|
||||
frees the memories pointed by `filename` and shows the window.
|
||||
If it fails, it outputs an error message and destroys the window.
|
||||
If this function succeeds, it inserts the contents into GtkTextBuffer,
|
||||
frees the buffer pointed by `contents`, sets the title of the window,
|
||||
frees the memories pointed by `filename` and then shows the window.
|
||||
If it fails, it outputs an error message and destroys the window, causing the program to quit.
|
||||
|
||||
## GtkNotebook
|
||||
|
||||
GtkNotebook is a container widget that contains multiple children with tabs in it.
|
||||
GtkNotebook is a container widget that uses tabs and contains multiple children.
|
||||
The child that is displayed depends on which tab has been selected.
|
||||
|
||||
![GtkNotebook](../image/screenshot_gtk_notebook.png)
|
||||
|
||||
Look at the screenshots above.
|
||||
The left one is a window at the startup.
|
||||
It shows the file `pr1.c`.
|
||||
The filename is in the left tab.
|
||||
After clicking on the right tab, the contents of `tfv1.c` appears.
|
||||
It is shown in the right of the screenshot.
|
||||
Looking at the screenshots above,
|
||||
the left one is the window at the startup.
|
||||
It shows the file `pr1.c` and the filename is in the left tab.
|
||||
After clicking on the right tab, the contents of the file `tfv1.c` are shown instead.
|
||||
This is shown in the right screenshot.
|
||||
|
||||
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
|
||||
Now I want to show you the program `tfv4.c`.
|
||||
The GtkNotebook widget is inserted as a child of GtkApplicationWindow and contains a GtkScrolledWindow
|
||||
for each file that is being displayed.
|
||||
The code to do this is given in `tfv4.c` and is:
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
|
@ -301,30 +301,28 @@ Now I want to show you the program `tfv4.c`.
|
|||
66 app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
|
||||
67 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
68 g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||
69 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
69 stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
70 g_object_unref (app);
|
||||
71 return stat;
|
||||
72 }
|
||||
73
|
||||
~~~
|
||||
|
||||
Most of the change is in the function `app_open`.
|
||||
Most of the changes are in the function `app_open`.
|
||||
The numbers at the left of the following items are line numbers in the source code.
|
||||
|
||||
- 11-13: Variables `nb`, `lab` and `nbp` are defined and points GtkNotebook, GtkLabel and GtkNotebookPage respectively.
|
||||
- 11-13: Variables `nb`, `lab` and `nbp` are defined and will point to a new GtkNotebook, GtkLabel and GtkNotebookPage widget respectively.
|
||||
- 23: The window's title is set to "file viewer".
|
||||
- 25: The size of the window is set to maximum because a big window is appropriate for file viewers.
|
||||
- 27-28 GtkNotebook is created and inserted to the GtkApplicationWindow as a child.
|
||||
- 30-59 For-loop. Each loop corresponds to an argument. And files[i] is GFile object with respect to the i-th argument.
|
||||
- 32-37 GtkScrollledWindow, GtkTextView are created and GtkTextBuffer is get from the GtkTextView.
|
||||
- 30-59 For-loop. Each loop corresponds to a filename argument, and `files[i]` is GFile object containing the i-th argument.
|
||||
- 32-37 GtkScrollledWindow, GtkTextView are created and GtkTextBuffer found from the new GtkTextView.
|
||||
GtkTextView is connected to GtkScrolledWindow as a child.
|
||||
They corresponds to each file, so they are created inside the for-loop.
|
||||
Each file gets their own copy of these widgets, so they are created inside the for-loop.
|
||||
- 39-40 inserts the contents of the file into GtkTextBuffer and frees the memory pointed by `contents`.
|
||||
- 41-43: Gets the filename and creates GtkLabel with the filename.
|
||||
Frees `filename`.
|
||||
- 41-43: Gets the filename and creates GtkLabel with the filename and then frees `filename`.
|
||||
- 44-45: If `filename` is NULL, creates GtkLabel with the empty string.
|
||||
- 46: Appends GtkScrolledWindow and GtkLabel to GtkNotebook.
|
||||
At the same time, a GtkNoteBookPage widget is created automatically.
|
||||
- 46: Appends GtkScrolledWindow as a page, with the tab GtkLabel, to GtkNotebook.
|
||||
At this time a GtkNoteBookPage widget is created automatically.
|
||||
The GtkScrolledWindow widget is connected to the GtkNotebookPage.
|
||||
Therefore, the structure is like this:
|
||||
|
||||
|
@ -332,18 +330,16 @@ Therefore, the structure is like this:
|
|||
GtkNotebook -- GtkNotebookPage -- GtkScrolledWindow
|
||||
~~~
|
||||
|
||||
- 47: Gets GtkNotebookPage widget and sets `nbp` to point the GtkNotebookPage.
|
||||
- 48: GtkNotebookPage has a property "tab-expand".
|
||||
- 47: Gets GtkNotebookPage widget and sets `nbp` to point to this GtkNotebookPage.
|
||||
- 48: GtkNotebookPage has a property set called "tab-expand".
|
||||
If it is set to TRUE then the tab expands horizontally as long as possible.
|
||||
If it is FALSE, then the width of the tab is determined by the size of the label.
|
||||
`g_object_set` is a general function to set properties in any objects.
|
||||
`g_object_set` is a general function to set properties in objects.
|
||||
See [GObject API Reference, g\_object\_set](https://docs.gtk.org/gobject/method.Object.set.html).
|
||||
- 49-51: If it fails to read the file, "No such file" message is outputted.
|
||||
Frees `filename`.
|
||||
- 52-53: If `filename` is NULL, "No valid file is given" message is outputted.
|
||||
- 49-51: If the file cannot be read, "No such file" message is displayed and the `filename` buffer is freed.
|
||||
- 52-53: If `filename` is NULL, the "No valid file is given" message is outputted.
|
||||
- 55-58: If at least one file was read, then the number of GtkNotebookPage is greater than zero.
|
||||
If it's true, it shows the window.
|
||||
If it's false, it destroys the window.
|
||||
|
||||
If it's false, it destroys the window, which causes the program to quit.
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 6](sec6.md), Next: [Section 8](sec8.md)
|
||||
|
|
119
src/sec6.src.md
119
src/sec6.src.md
|
@ -1,14 +1,17 @@
|
|||
# String and memory management
|
||||
|
||||
GtkTextView and GtkTextBuffer have functions that have string parameters or return a string.
|
||||
The knowledge of strings and memory management is very important for us to understand the functions above.
|
||||
GtkTextView and GtkTextBuffer have functions that use string parameters or return a string.
|
||||
The knowledge of strings and memory management is useful to understand how to use these functions.
|
||||
|
||||
## String and memory
|
||||
|
||||
String is an array of characters that is terminated with '\0'.
|
||||
String is not a C type such as char, int, float or double.
|
||||
But the pointer to a character array behaves like a string type of other languages.
|
||||
So, the pointer is often called string.
|
||||
A String is an array of characters that is terminated with '\0'.
|
||||
Strings are not a C type such as char, int, float or double,
|
||||
but exist as a pointer to a character array. They behaves like a string type
|
||||
which you may be familiar from other languages.
|
||||
So, this pointer is often called 'a string'.
|
||||
|
||||
In the following, `a` and `b` defined as character arrays, and are strings.
|
||||
|
||||
~~~C
|
||||
char a[10], *b;
|
||||
|
@ -25,46 +28,50 @@ b = a;
|
|||
/* *(++b) is 'e' */
|
||||
~~~
|
||||
|
||||
The array `a` has `char` elements and the size is ten.
|
||||
The array `a` has `char` elements and the size of ten.
|
||||
The first six elements are 'H', 'e', 'l', 'l', 'o' and '\0'.
|
||||
This array represents a string "Hello".
|
||||
This array represents the string "Hello".
|
||||
The first five elements are character codes that correspond to the characters.
|
||||
The sixth element is '\0' that is the same as zero.
|
||||
And it indicates that the string ends there.
|
||||
The size of the array is 10, so 4 bytes aren't used, but it's OK.
|
||||
They are just ignored.
|
||||
The sixth element is '\0', which is the same as zero,
|
||||
and indicates that the string ends there.
|
||||
The size of the array is 10, so 4 bytes aren't used, but that's OK,
|
||||
they are just ignored.
|
||||
|
||||
The variable 'b' is a pointer to a character.
|
||||
Because `a` is assigned to `b`, `a` and `b` point the same character ('H').
|
||||
Because `b` is assigned to be `a`, `a` and `b` point the same character ('H').
|
||||
The variable `a` is defined as an array and it can't be changed.
|
||||
It always point the top address of the array.
|
||||
On the other hand, pointers are mutable, so `b` can change itself.
|
||||
It is possible to write `++b` (`b` is increased by one).
|
||||
On the other hand, 'b' is a pointer, which is mutable, so `b` can be change.
|
||||
It is then possible to write statements like `++b`, which means take the value in b (n address),
|
||||
increase it by one, and store that back in `b`.
|
||||
|
||||
If a pointer is NULL, it points nothing.
|
||||
If a pointer is NULL, it points to nothing.
|
||||
So, the pointer is not a string.
|
||||
Programs with string will include bugs if you aren't careful about NULL pointer.
|
||||
A NULL string on the other hand will be a pointer which points to a location
|
||||
that contains `\0`, which is a string of length 0 (or "").
|
||||
Programs that use strings will include bugs if you aren't careful when using NULL pointers.
|
||||
|
||||
Another annoying problem is memory that a string is allocated.
|
||||
There are four cases.
|
||||
Another annoying problem is the memory that a string is allocated.
|
||||
There are four cases:
|
||||
|
||||
- The string is read only.
|
||||
- The string is in static memory area.
|
||||
- The string is in stack.
|
||||
- The string is read only;
|
||||
- The string is in static memory area;
|
||||
- The string is in stack; and
|
||||
- The string is in memory allocated from the heap area.
|
||||
|
||||
## Read only string
|
||||
|
||||
A string literal in C program is surrounded by double quotes.
|
||||
A string literal in a C program is surrounded by double quotes and written as the following:
|
||||
|
||||
~~~C
|
||||
char *s;
|
||||
s = "Hello"
|
||||
~~~
|
||||
|
||||
"Hello" is a string literal.
|
||||
"Hello" is a string literal, and is stored in program memory.
|
||||
A string literal is read only.
|
||||
In the program above, `s` points the string literal.
|
||||
|
||||
So, the following program is illegal.
|
||||
|
||||
~~~C
|
||||
|
@ -74,18 +81,22 @@ So, the following program is illegal.
|
|||
The result is undefined.
|
||||
Probably a bad thing will happen, for example, a segmentation fault.
|
||||
|
||||
NOTE: The memory of the literal string is allocated when the program is
|
||||
compiled. It is possible to view all the literal strings defined in your program
|
||||
by using the `string` command.
|
||||
|
||||
## Strings defined as arrays
|
||||
|
||||
If a string is defined as an array, it's in static memory area or stack.
|
||||
It depends on the class of the array.
|
||||
If a string is defined as an array, it's in either stored in the static memory area or stack.
|
||||
This depends on the class of the array.
|
||||
If the array's class is `static`, then it's placed in static memory area.
|
||||
It keeps its value and remains for the life of the program.
|
||||
This area is writable.
|
||||
This allocation and memory address is fixed for the life of the program.
|
||||
This area can be changed and is writable.
|
||||
|
||||
If the array's class is `auto`, then it's placed in stack.
|
||||
If the array is defined in a function, its default class is `auto`.
|
||||
The stack area will disappear when the function returns to the caller.
|
||||
stack is writable.
|
||||
If the array is defined inside a function, its default class is `auto`.
|
||||
The stack area will disappear when the function exits and returns to the caller.
|
||||
Arrays defined on the stack are writable.
|
||||
|
||||
~~~C
|
||||
|
||||
|
@ -103,30 +114,30 @@ print_strings (void) {
|
|||
}
|
||||
~~~
|
||||
|
||||
The array `a` is defined externally to functions.
|
||||
The array `a` is defined externally to a function and is global in its scope.
|
||||
Such variables are placed in static memory area even if the `static` class is left out.
|
||||
First, the compiler calculates the number of the elements in the right hand side.
|
||||
It is six.
|
||||
The compiler allocates six bytes memory in the static memory area and copies the data to the memory.
|
||||
The compiler calculates the number of the elements in the right hand side (six),
|
||||
and then creates code that allocates six bytes in the static memory area and copies the data to this memory.
|
||||
|
||||
The array `b` is defined inside the function.
|
||||
So, its class is `auto`.
|
||||
The array `b` is defined inside the function
|
||||
so its class is `auto`.
|
||||
The compiler calculates the number of the elements in the string literal.
|
||||
It is six because the string is zero terminated.
|
||||
The compiler allocates six bytes memory in the stack and copies the data to the memory.
|
||||
It has six elements as the zero termination character is also included.
|
||||
The compiler creates code which allocates six bytes memory in the stack and copies the data to the memory.
|
||||
|
||||
Both `a` and `b` are writable.
|
||||
|
||||
The memory is managed by the executable program.
|
||||
You don't need to program to allocate or free the memory for `a` and `b`.
|
||||
The array `a` remains for the life of the program.
|
||||
The array `b` disappears when the function returns to the caller.
|
||||
You don't need your program to allocate or free the memory for `a` and `b`.
|
||||
The array `a` is created then the program is first run and remains for the life of the program.
|
||||
The array `b` is created on the stack then the function is called, disappears when the function returns.
|
||||
|
||||
## Strings in the heap area
|
||||
|
||||
You can get memory from the heap area and put back the memory to the heap area.
|
||||
You can also get, use and release memory from the heap area.
|
||||
The standard C library provides `malloc` to get memory and `free` to put back memory.
|
||||
Similarly, GLib provides `g_new` and `g_free`.
|
||||
GLib provides the functions `g_new` and `g_free` to do the same thing, with support for
|
||||
some additional Glib functionality.
|
||||
|
||||
~~~C
|
||||
g_new (struct_type, n_struct)
|
||||
|
@ -163,7 +174,7 @@ If `mem` is NULL, `g_free` does nothing.
|
|||
`gpointer` is a type of general pointer.
|
||||
It is the same as `void *`.
|
||||
This pointer can be casted to any pointer type.
|
||||
Conversely, any pointer type can be casted to gpointer.
|
||||
Conversely, any pointer type can be casted to `gpointer`.
|
||||
|
||||
~~~C
|
||||
g_free (s);
|
||||
|
@ -173,10 +184,10 @@ g_free (t);
|
|||
/* Frees the memory allocated to t. */
|
||||
~~~
|
||||
|
||||
If the argument doesn't point allocated memory, it will cause an error, for example, segmentation fault.
|
||||
If the argument doesn't point allocated memory it will cause an error, specifically, a segmentation fault.
|
||||
|
||||
Some Glib functions allocate memory.
|
||||
For example, `g_strdup` allocates memory and copy a string given as an argument.
|
||||
For example, `g_strdup` allocates memory and copies a string given as an argument.
|
||||
|
||||
~~~C
|
||||
char *s;
|
||||
|
@ -194,8 +205,11 @@ The following is extracted from the reference.
|
|||
|
||||
> The returned string should be freed with `g_free()` when no longer needed.
|
||||
|
||||
The reference usually describes if the returned value needs to be freed.
|
||||
If you forget to free the allocated memory, it causes memory leak.
|
||||
The function reference will describe if the returned value needs to be freed.
|
||||
If you forget to free the allocated memory it will remain allocated. Repeated use will cause
|
||||
more memory to be allocated to the program, which will grow over time. This is called a memory leak,
|
||||
and the only way to address this bug is to close the program (and restart it),
|
||||
which will automatically release all of the programs memory back to the system.
|
||||
|
||||
Some GLib functions return a string which mustn't be freed by the caller.
|
||||
|
||||
|
@ -205,14 +219,13 @@ g_quark_to_string (GQuark quark);
|
|||
~~~
|
||||
|
||||
This function returns `const char*` type.
|
||||
The qualifier `const` means immutable.
|
||||
Therefore, the characters pointed by the returned value aren't be allowed to change or free.
|
||||
The qualifier `const` means that the returned value is immutable.
|
||||
The characters pointed by the returned value aren't be allowed to be changed or freed.
|
||||
|
||||
If a variable is qualified with `const`, the variable can't be assigned except initialization.
|
||||
If a variable is qualified with `const`, the variable can't be assigned except during initialization.
|
||||
|
||||
~~~C
|
||||
const int x = 10; /* initialization is OK. */
|
||||
|
||||
x = 20; /* This is illegal because x is qualified with const */
|
||||
~~~
|
||||
|
||||
|
|
154
src/sec7.src.md
154
src/sec7.src.md
|
@ -4,21 +4,22 @@
|
|||
|
||||
### G\_APPLICATION\_HANDLES\_OPEN flag
|
||||
|
||||
GtkTextView, GtkTextBuffer and GtkScrolledWindow have given us a minimum editor in the previous section.
|
||||
Next, we will add a function to read a file and remake the program into a file viewer.
|
||||
There are many ways to implement the function.
|
||||
Because this is a tutorial for beginners, we'll take the easiest one.
|
||||
The GtkTextView, GtkTextBuffer and GtkScrolledWindow widgets have given us a minimum editor
|
||||
in the previous section.
|
||||
We will now add a function to read a file and rework the program into a file viewer.
|
||||
There are many ways to implement the function and
|
||||
because this is a tutorial for beginners, we'll take the easiest one.
|
||||
|
||||
When the program starts, we give a filename as an argument.
|
||||
When the program starts, we will give the filename to open as an argument.
|
||||
|
||||
$ ./a.out filename
|
||||
|
||||
Then it opens the file and inserts its contents into the GtkTextBuffer.
|
||||
It will open the file and insert its contents into the GtkTextBuffer.
|
||||
|
||||
At the beginning of the implementation, we need to know how GtkApplication (or GApplication) recognizes arguments.
|
||||
It is described in the [GIO API Reference, Application](https://docs.gtk.org/gio/class.Application.html).
|
||||
To do this, we need to know how GtkApplication (or GApplication) recognizes arguments.
|
||||
This is described in the [GIO API Reference, Application](https://docs.gtk.org/gio/class.Application.html).
|
||||
|
||||
When GtkApplication is created, a flag (its type is GApplicationFlags) is given as an argument.
|
||||
When GtkApplication is created, a flag (with the type GApplicationFlags) is provided as an argument.
|
||||
|
||||
~~~C
|
||||
GtkApplication *
|
||||
|
@ -26,9 +27,9 @@ gtk_application_new (const gchar *application_id, GApplicationFlags flags);
|
|||
~~~
|
||||
|
||||
This tutorial explains only two flags, `G_APPLICATION_FLAGS_NONE` and `G_APPLICATION_HANDLES_OPEN`.
|
||||
If you want to handle command line arguments, `G_APPLICATION_HANDLES_COMMAND_LINE` flag is what you need.
|
||||
How to program it is written in [GIO API Reference, g\_application\_run](https://docs.gtk.org/gio/method.Application.run.html).
|
||||
And the flag is described in the [GIO API Reference, ApplicationFlags](https://docs.gtk.org/gio/flags.ApplicationFlags.html).
|
||||
If you want to handle command line arguments, the `G_APPLICATION_HANDLES_COMMAND_LINE` flag is what you need.
|
||||
How to use the new application method is described in [GIO API Reference, g\_application\_run](https://docs.gtk.org/gio/method.Application.run.html),
|
||||
and the flag is described in the [GIO API Reference, ApplicationFlags](https://docs.gtk.org/gio/flags.ApplicationFlags.html).
|
||||
|
||||
~~~
|
||||
GApplicationFlags' Members
|
||||
|
@ -39,18 +40,15 @@ G_APPLICATION_HANDLES_OPEN This application handles opening files (in the prima
|
|||
... ... ...
|
||||
~~~
|
||||
|
||||
There are ten flags.
|
||||
But we only need two of them so far.
|
||||
We've already used `G_APPLICATION_FLAGS_NONE`.
|
||||
It is the simplest option.
|
||||
No argument is allowed.
|
||||
If you give arguments and run the application, then error occurs.
|
||||
There are ten flags in total, but we only need two of them so far.
|
||||
We've already used `G_APPLICATION_FLAGS_NONE`, as
|
||||
it is the simplest option, and no arguments are allowed.
|
||||
If you provide arguments when running the application, an error will occur.
|
||||
|
||||
`G_APPLICATION_HANDLES_OPEN` is the second simplest option.
|
||||
The flag `G_APPLICATION_HANDLES_OPEN` is the second simplest option.
|
||||
It allows arguments but only files.
|
||||
The application assumes all the arguments are filenames.
|
||||
|
||||
Now we use this flag when creating GtkApplication.
|
||||
The application assumes all the arguments are filenames and we will use this flag when creating
|
||||
our GtkApplication.
|
||||
|
||||
~~~C
|
||||
app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||
|
@ -58,12 +56,12 @@ app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPE
|
|||
|
||||
### open signal
|
||||
|
||||
When the application starts, two signals are possible.
|
||||
Now, when the application starts, two signals can be emitted.
|
||||
|
||||
- activate signal --- This signal is emitted when there's no argument.
|
||||
- open signal --- This signal is emitted when there is at least one argument.
|
||||
|
||||
The handler of "open" signal is defined as follows.
|
||||
The handler of the "open" signal is defined as follows.
|
||||
|
||||
~~~C
|
||||
void user_function (GApplication *application,
|
||||
|
@ -81,22 +79,22 @@ The parameters are:
|
|||
- `hint` --- a hint provided by the calling instance (usually it can be ignored)
|
||||
- `user_data` --- user data set when the signal handler was connected.
|
||||
|
||||
The way how to read a file (GFile) will be described in the next subsection.
|
||||
How to read a specified file (GFile) will be described next.
|
||||
|
||||
## Making a file viewer
|
||||
|
||||
### What is a file viewer?
|
||||
|
||||
A file viewer is a program that shows a text file given as an argument.
|
||||
It works as follows.
|
||||
A file viewer is a program that displays the text file that is given as an argument.
|
||||
Our file viewer will work as follows.
|
||||
|
||||
- If it is given arguments, it recognizes the first argument as a filename and opens it.
|
||||
- If opening the file succeeds, it reads the contents of the file and inserts it to GtkTextBuffer and shows the window.
|
||||
- If it fails to open the file, shows an error message and quits.
|
||||
- If there's no argument, it shows an error message and quits.
|
||||
- If there are two or more arguments, the second one and after are ignored.
|
||||
- When arguments are given, it treats the first argument as a filename and opens it.
|
||||
- If opening the file succeeds, it reads the contents of the file and inserts it to GtkTextBuffer and then shows the window.
|
||||
- If it fails to open the file, it will show an error message and quit.
|
||||
- If there's no argument, it will shows an error message and quit.
|
||||
- If there are two or more arguments, the second one and any others are ignored.
|
||||
|
||||
The program is as follows.
|
||||
The program which does this is shown below.
|
||||
|
||||
@@@include
|
||||
tfv/tfv3.c
|
||||
|
@ -110,25 +108,25 @@ Then compile and run it.
|
|||
|
||||
![File viewer](../image/screenshot_tfv3.png){width=6.3cm height=5.325cm}
|
||||
|
||||
Now I want to explain the program `tfv3.c`.
|
||||
First, the function `main` changes in only two lines from the previous version.
|
||||
Let's explain how the program `tfv3.c` works.
|
||||
First, the function `main` has only two changes from the previous version.
|
||||
|
||||
- `G_APPLICATION_FLAGS_NONE` is replaced by `G_APPLICATION_HANDLES_OPEN`.
|
||||
- `G_APPLICATION_FLAGS_NONE` is replaced by `G_APPLICATION_HANDLES_OPEN`; and
|
||||
- `g_signal_connect (app, "open", G_CALLBACK (on_open), NULL)` is added.
|
||||
|
||||
Next, the handler `app_activate` is now very simple.
|
||||
It just outputs the error message.
|
||||
The application quits immediately because no window is created.
|
||||
Next, the handler `app_activate` is added and is very simple.
|
||||
It just outputs the error message and
|
||||
the application quits immediately because no window is created.
|
||||
|
||||
The point is the handler `app_open`.
|
||||
The main functionality is the in the handler `app_open`. It
|
||||
|
||||
- It creates GtkApplicationWindow, GtkScrolledWindow, GtkTextView and GtkTextBuffer and connects them.
|
||||
- Sets wrap mode to `GTK_WRAP_WORD_CHAR` in GtktextView.
|
||||
- Sets GtkTextView to non-editable because the program isn't an editor but only a viewer.
|
||||
- Reads the file and inserts the text into GtkTextBuffer (this will be explained in detail later).
|
||||
- If the file is not opened then outputs an error message and destroys the window. It makes the application quit.
|
||||
- Creates GtkApplicationWindow, GtkScrolledWindow, GtkTextView and GtkTextBuffer and connects them together;
|
||||
- Sets wrap mode to `GTK_WRAP_WORD_CHAR` in GtktextView;
|
||||
- Sets GtkTextView to non-editable because the program isn't an editor but only a viewer;
|
||||
- Reads the file and inserts the text into GtkTextBuffer (this will be explained in detail later); and
|
||||
- If the file is not opened then outputs an error message and destroys the window. This makes the application quit.
|
||||
|
||||
The file reading part of the program is shown again below.
|
||||
The following is the important file reading part of the program and is shown again below.
|
||||
|
||||
~~~C
|
||||
if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
||||
|
@ -148,51 +146,53 @@ if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
|||
}
|
||||
~~~
|
||||
|
||||
The function `g_file_load_contents` loads the file contents into a buffer, which is automatically allocated, and sets `contents` to point the buffer.
|
||||
And the length of the buffer is set to `length`.
|
||||
It returns `TRUE` if the file's contents are successfully loaded. `FALSE` if an error happens.
|
||||
The function `g_file_load_contents` loads the file contents into a buffer,
|
||||
which is automatically allocated and sets `contents` to point that buffer.
|
||||
The length of the buffer is set to `length`.
|
||||
It returns `TRUE` if the file's contents are successfully loaded and `FALSE` if an error occurs.
|
||||
|
||||
If the function succeeds, it inserts the contents into GtkTextBuffer, frees the buffer memories pointed by `contents`, sets the title of the window,
|
||||
frees the memories pointed by `filename` and shows the window.
|
||||
If it fails, it outputs an error message and destroys the window.
|
||||
If this function succeeds, it inserts the contents into GtkTextBuffer,
|
||||
frees the buffer pointed by `contents`, sets the title of the window,
|
||||
frees the memories pointed by `filename` and then shows the window.
|
||||
If it fails, it outputs an error message and destroys the window, causing the program to quit.
|
||||
|
||||
## GtkNotebook
|
||||
|
||||
GtkNotebook is a container widget that contains multiple children with tabs in it.
|
||||
GtkNotebook is a container widget that uses tabs and contains multiple children.
|
||||
The child that is displayed depends on which tab has been selected.
|
||||
|
||||
![GtkNotebook](../image/screenshot_gtk_notebook.png){width=13.2cm height=5.325cm}
|
||||
|
||||
Look at the screenshots above.
|
||||
The left one is a window at the startup.
|
||||
It shows the file `pr1.c`.
|
||||
The filename is in the left tab.
|
||||
After clicking on the right tab, the contents of `tfv1.c` appears.
|
||||
It is shown in the right of the screenshot.
|
||||
Looking at the screenshots above,
|
||||
the left one is the window at the startup.
|
||||
It shows the file `pr1.c` and the filename is in the left tab.
|
||||
After clicking on the right tab, the contents of the file `tfv1.c` are shown instead.
|
||||
This is shown in the right screenshot.
|
||||
|
||||
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
|
||||
Now I want to show you the program `tfv4.c`.
|
||||
The GtkNotebook widget is inserted as a child of GtkApplicationWindow and contains a GtkScrolledWindow
|
||||
for each file that is being displayed.
|
||||
The code to do this is given in `tfv4.c` and is:
|
||||
|
||||
@@@include
|
||||
tfv/tfv4.c
|
||||
@@@
|
||||
|
||||
Most of the change is in the function `app_open`.
|
||||
Most of the changes are in the function `app_open`.
|
||||
The numbers at the left of the following items are line numbers in the source code.
|
||||
|
||||
- 11-13: Variables `nb`, `lab` and `nbp` are defined and points GtkNotebook, GtkLabel and GtkNotebookPage respectively.
|
||||
- 11-13: Variables `nb`, `lab` and `nbp` are defined and will point to a new GtkNotebook, GtkLabel and GtkNotebookPage widget respectively.
|
||||
- 23: The window's title is set to "file viewer".
|
||||
- 25: The size of the window is set to maximum because a big window is appropriate for file viewers.
|
||||
- 27-28 GtkNotebook is created and inserted to the GtkApplicationWindow as a child.
|
||||
- 30-59 For-loop. Each loop corresponds to an argument. And files[i] is GFile object with respect to the i-th argument.
|
||||
- 32-37 GtkScrollledWindow, GtkTextView are created and GtkTextBuffer is get from the GtkTextView.
|
||||
- 30-59 For-loop. Each loop corresponds to a filename argument, and `files[i]` is GFile object containing the i-th argument.
|
||||
- 32-37 GtkScrollledWindow, GtkTextView are created and GtkTextBuffer found from the new GtkTextView.
|
||||
GtkTextView is connected to GtkScrolledWindow as a child.
|
||||
They corresponds to each file, so they are created inside the for-loop.
|
||||
Each file gets their own copy of these widgets, so they are created inside the for-loop.
|
||||
- 39-40 inserts the contents of the file into GtkTextBuffer and frees the memory pointed by `contents`.
|
||||
- 41-43: Gets the filename and creates GtkLabel with the filename.
|
||||
Frees `filename`.
|
||||
- 41-43: Gets the filename and creates GtkLabel with the filename and then frees `filename`.
|
||||
- 44-45: If `filename` is NULL, creates GtkLabel with the empty string.
|
||||
- 46: Appends GtkScrolledWindow and GtkLabel to GtkNotebook.
|
||||
At the same time, a GtkNoteBookPage widget is created automatically.
|
||||
- 46: Appends GtkScrolledWindow as a page, with the tab GtkLabel, to GtkNotebook.
|
||||
At this time a GtkNoteBookPage widget is created automatically.
|
||||
The GtkScrolledWindow widget is connected to the GtkNotebookPage.
|
||||
Therefore, the structure is like this:
|
||||
|
||||
|
@ -200,16 +200,14 @@ Therefore, the structure is like this:
|
|||
GtkNotebook -- GtkNotebookPage -- GtkScrolledWindow
|
||||
~~~
|
||||
|
||||
- 47: Gets GtkNotebookPage widget and sets `nbp` to point the GtkNotebookPage.
|
||||
- 48: GtkNotebookPage has a property "tab-expand".
|
||||
- 47: Gets GtkNotebookPage widget and sets `nbp` to point to this GtkNotebookPage.
|
||||
- 48: GtkNotebookPage has a property set called "tab-expand".
|
||||
If it is set to TRUE then the tab expands horizontally as long as possible.
|
||||
If it is FALSE, then the width of the tab is determined by the size of the label.
|
||||
`g_object_set` is a general function to set properties in any objects.
|
||||
`g_object_set` is a general function to set properties in objects.
|
||||
See [GObject API Reference, g\_object\_set](https://docs.gtk.org/gobject/method.Object.set.html).
|
||||
- 49-51: If it fails to read the file, "No such file" message is outputted.
|
||||
Frees `filename`.
|
||||
- 52-53: If `filename` is NULL, "No valid file is given" message is outputted.
|
||||
- 49-51: If the file cannot be read, "No such file" message is displayed and the `filename` buffer is freed.
|
||||
- 52-53: If `filename` is NULL, the "No valid file is given" message is outputted.
|
||||
- 55-58: If at least one file was read, then the number of GtkNotebookPage is greater than zero.
|
||||
If it's true, it shows the window.
|
||||
If it's false, it destroys the window.
|
||||
|
||||
If it's false, it destroys the window, which causes the program to quit.
|
||||
|
|
|
@ -8,16 +8,16 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
gchar *text;
|
||||
|
||||
text =
|
||||
"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.\n"
|
||||
"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.\n"
|
||||
"His wife was surprized at his tale. "
|
||||
"They were very happy because they had no children. "
|
||||
;
|
||||
"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.\n"
|
||||
"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.\n"
|
||||
"His wife was surprized at his tale. "
|
||||
"They were very happy because they had no children. "
|
||||
;
|
||||
win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
|
@ -39,7 +39,7 @@ main (int argc, char **argv) {
|
|||
|
||||
app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
|
|
@ -9,16 +9,16 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
gchar *text;
|
||||
|
||||
text =
|
||||
"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.\n"
|
||||
"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.\n"
|
||||
"His wife was surprized at his tale. "
|
||||
"They were very happy because they had no children. "
|
||||
;
|
||||
"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.\n"
|
||||
"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.\n"
|
||||
"His wife was surprized at his tale. "
|
||||
"They were very happy because they had no children. "
|
||||
;
|
||||
win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
|
@ -43,7 +43,7 @@ main (int argc, char **argv) {
|
|||
|
||||
app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
|
|
@ -52,8 +52,7 @@ main (int argc, char **argv) {
|
|||
app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||
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);
|
||||
stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,7 @@ main (int argc, char **argv) {
|
|||
app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
|
||||
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);
|
||||
stat = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue