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
|
@ -52,7 +52,7 @@ See the sample program `tfv1.c` below.
|
||||||
39
|
39
|
||||||
40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||||
41 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
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);
|
43 g_object_unref (app);
|
||||||
44 return stat;
|
44 return stat;
|
||||||
45 }
|
45 }
|
||||||
|
@ -159,7 +159,7 @@ Here is the complete code of `tfv2.c`.
|
||||||
43
|
43
|
||||||
44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||||
45 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
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);
|
47 g_object_unref (app);
|
||||||
48 return stat;
|
48 return stat;
|
||||||
49 }
|
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
|
# String and memory management
|
||||||
|
|
||||||
GtkTextView and GtkTextBuffer have functions that have string parameters or return a string.
|
GtkTextView and GtkTextBuffer have functions that use string parameters or return a string.
|
||||||
The knowledge of strings and memory management is very important for us to understand the functions above.
|
The knowledge of strings and memory management is useful to understand how to use these functions.
|
||||||
|
|
||||||
## String and memory
|
## String and memory
|
||||||
|
|
||||||
String is an array of characters that is terminated with '\0'.
|
A String is an array of characters that is terminated with '\0'.
|
||||||
String is not a C type such as char, int, float or double.
|
Strings are 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.
|
but exist as a pointer to a character array. They behaves like a string type
|
||||||
So, the pointer is often called string.
|
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
|
~~~C
|
||||||
char a[10], *b;
|
char a[10], *b;
|
||||||
|
@ -27,46 +30,50 @@ b = a;
|
||||||
/* *(++b) is 'e' */
|
/* *(++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'.
|
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 first five elements are character codes that correspond to the characters.
|
||||||
The sixth element is '\0' that is the same as zero.
|
The sixth element is '\0', which is the same as zero,
|
||||||
And it indicates that the string ends there.
|
and indicates that the string ends there.
|
||||||
The size of the array is 10, so 4 bytes aren't used, but it's OK.
|
The size of the array is 10, so 4 bytes aren't used, but that's OK,
|
||||||
They are just ignored.
|
they are just ignored.
|
||||||
|
|
||||||
The variable 'b' is a pointer to a character.
|
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.
|
The variable `a` is defined as an array and it can't be changed.
|
||||||
It always point the top address of the array.
|
It always point the top address of the array.
|
||||||
On the other hand, pointers are mutable, so `b` can change itself.
|
On the other hand, 'b' is a pointer, which is mutable, so `b` can be change.
|
||||||
It is possible to write `++b` (`b` is increased by one).
|
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.
|
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.
|
Another annoying problem is the memory that a string is allocated.
|
||||||
There are four cases.
|
There are four cases:
|
||||||
|
|
||||||
- The string is read only.
|
- The string is read only;
|
||||||
- The string is in static memory area.
|
- The string is in static memory area;
|
||||||
- The string is in stack.
|
- The string is in stack; and
|
||||||
- The string is in memory allocated from the heap area.
|
- The string is in memory allocated from the heap area.
|
||||||
|
|
||||||
## Read only string
|
## 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
|
~~~C
|
||||||
char *s;
|
char *s;
|
||||||
s = "Hello"
|
s = "Hello"
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
"Hello" is a string literal.
|
"Hello" is a string literal, and is stored in program memory.
|
||||||
A string literal is read only.
|
A string literal is read only.
|
||||||
In the program above, `s` points the string literal.
|
In the program above, `s` points the string literal.
|
||||||
|
|
||||||
So, the following program is illegal.
|
So, the following program is illegal.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
|
@ -76,18 +83,22 @@ So, the following program is illegal.
|
||||||
The result is undefined.
|
The result is undefined.
|
||||||
Probably a bad thing will happen, for example, a segmentation fault.
|
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
|
## Strings defined as arrays
|
||||||
|
|
||||||
If a string is defined as an array, it's in static memory area or stack.
|
If a string is defined as an array, it's in either stored in the static memory area or stack.
|
||||||
It depends on the class of the array.
|
This depends on the class of the array.
|
||||||
If the array's class is `static`, then it's placed in static memory area.
|
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 allocation and memory address is fixed for the life of the program.
|
||||||
This area is writable.
|
This area can be changed and is writable.
|
||||||
|
|
||||||
If the array's class is `auto`, then it's placed in stack.
|
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`.
|
If the array is defined inside a function, its default class is `auto`.
|
||||||
The stack area will disappear when the function returns to the caller.
|
The stack area will disappear when the function exits and returns to the caller.
|
||||||
stack is writable.
|
Arrays defined on the stack are writable.
|
||||||
|
|
||||||
~~~C
|
~~~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.
|
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.
|
The compiler calculates the number of the elements in the right hand side (six),
|
||||||
It is six.
|
and then creates code that allocates six bytes in the static memory area and copies the data to this memory.
|
||||||
The compiler allocates six bytes memory in the static memory area and copies the data to the memory.
|
|
||||||
|
|
||||||
The array `b` is defined inside the function.
|
The array `b` is defined inside the function
|
||||||
So, its class is `auto`.
|
so its class is `auto`.
|
||||||
The compiler calculates the number of the elements in the string literal.
|
The compiler calculates the number of the elements in the string literal.
|
||||||
It is six because the string is zero terminated.
|
It has six elements as the zero termination character is also included.
|
||||||
The compiler allocates six bytes memory in the stack and copies the data to the memory.
|
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.
|
Both `a` and `b` are writable.
|
||||||
|
|
||||||
The memory is managed by the executable program.
|
The memory is managed by the executable program.
|
||||||
You don't need to program to allocate or free the memory for `a` and `b`.
|
You don't need your program to allocate or free the memory for `a` and `b`.
|
||||||
The array `a` remains for the life of the program.
|
The array `a` is created then the program is first run and remains for the life of the program.
|
||||||
The array `b` disappears when the function returns to the caller.
|
The array `b` is created on the stack then the function is called, disappears when the function returns.
|
||||||
|
|
||||||
## Strings in the heap area
|
## 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.
|
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
|
~~~C
|
||||||
g_new (struct_type, n_struct)
|
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.
|
`gpointer` is a type of general pointer.
|
||||||
It is the same as `void *`.
|
It is the same as `void *`.
|
||||||
This pointer can be casted to any pointer type.
|
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
|
~~~C
|
||||||
g_free (s);
|
g_free (s);
|
||||||
|
@ -175,10 +186,10 @@ g_free (t);
|
||||||
/* Frees the memory allocated to 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.
|
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
|
~~~C
|
||||||
char *s;
|
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 returned string should be freed with `g_free()` when no longer needed.
|
||||||
|
|
||||||
The reference usually describes if the returned value needs to be freed.
|
The function reference will describe if the returned value needs to be freed.
|
||||||
If you forget to free the allocated memory, it causes memory leak.
|
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.
|
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.
|
This function returns `const char*` type.
|
||||||
The qualifier `const` means immutable.
|
The qualifier `const` means that the returned value is immutable.
|
||||||
Therefore, the characters pointed by the returned value aren't be allowed to change or free.
|
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
|
~~~C
|
||||||
const int x = 10; /* initialization is OK. */
|
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 */
|
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)
|
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
|
### G\_APPLICATION\_HANDLES\_OPEN flag
|
||||||
|
|
||||||
GtkTextView, GtkTextBuffer and GtkScrolledWindow have given us a minimum editor in the previous section.
|
The GtkTextView, GtkTextBuffer and GtkScrolledWindow widgets have given us a minimum editor
|
||||||
Next, we will add a function to read a file and remake the program into a file viewer.
|
in the previous section.
|
||||||
There are many ways to implement the function.
|
We will now add a function to read a file and rework the program into a file viewer.
|
||||||
Because this is a tutorial for beginners, we'll take the easiest one.
|
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
|
$ ./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.
|
To do this, 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).
|
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
|
~~~C
|
||||||
GtkApplication *
|
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`.
|
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.
|
If you want to handle command line arguments, the `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).
|
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).
|
and the flag is described in the [GIO API Reference, ApplicationFlags](https://docs.gtk.org/gio/flags.ApplicationFlags.html).
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
GApplicationFlags' Members
|
GApplicationFlags' Members
|
||||||
|
@ -41,18 +42,15 @@ G_APPLICATION_HANDLES_OPEN This application handles opening files (in the prima
|
||||||
... ... ...
|
... ... ...
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
There are ten flags.
|
There are ten flags in total, but we only need two of them so far.
|
||||||
But we only need two of them so far.
|
We've already used `G_APPLICATION_FLAGS_NONE`, as
|
||||||
We've already used `G_APPLICATION_FLAGS_NONE`.
|
it is the simplest option, and no arguments are allowed.
|
||||||
It is the simplest option.
|
If you provide arguments when running the application, an error will occur.
|
||||||
No argument is allowed.
|
|
||||||
If you give arguments and run the application, then error occurs.
|
|
||||||
|
|
||||||
`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.
|
It allows arguments but only files.
|
||||||
The application assumes all the arguments are filenames.
|
The application assumes all the arguments are filenames and we will use this flag when creating
|
||||||
|
our GtkApplication.
|
||||||
Now we use this flag when creating GtkApplication.
|
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
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
|
### 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.
|
- activate signal --- This signal is emitted when there's no argument.
|
||||||
- open signal --- This signal is emitted when there is at least one 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
|
~~~C
|
||||||
void user_function (GApplication *application,
|
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)
|
- `hint` --- a hint provided by the calling instance (usually it can be ignored)
|
||||||
- `user_data` --- user data set when the signal handler was connected.
|
- `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
|
## Making a file viewer
|
||||||
|
|
||||||
### What is a file viewer?
|
### What is a file viewer?
|
||||||
|
|
||||||
A file viewer is a program that shows a text file given as an argument.
|
A file viewer is a program that displays the text file that is given as an argument.
|
||||||
It works as follows.
|
Our file viewer will work as follows.
|
||||||
|
|
||||||
- If it is given arguments, it recognizes the first argument as a filename and opens it.
|
- 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 shows the window.
|
- 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, shows an error message and quits.
|
- If it fails to open the file, it will show an error message and quit.
|
||||||
- If there's no argument, it shows an error message and quits.
|
- If there's no argument, it will shows an error message and quit.
|
||||||
- If there are two or more arguments, the second one and after are ignored.
|
- 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
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
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);
|
52 app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||||
53 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
53 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
54 g_signal_connect (app, "open", G_CALLBACK (app_open), 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);
|
56 g_object_unref (app);
|
||||||
57 return stat;
|
57 return stat;
|
||||||
58 }
|
58 }
|
||||||
59
|
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Save it as `tfv3.c`.
|
Save it as `tfv3.c`.
|
||||||
|
@ -170,25 +167,25 @@ Then compile and run it.
|
||||||
|
|
||||||
![File viewer](../image/screenshot_tfv3.png)
|
![File viewer](../image/screenshot_tfv3.png)
|
||||||
|
|
||||||
Now I want to explain the program `tfv3.c`.
|
Let's explain how the program `tfv3.c` works.
|
||||||
First, the function `main` changes in only two lines from the previous version.
|
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.
|
- `g_signal_connect (app, "open", G_CALLBACK (on_open), NULL)` is added.
|
||||||
|
|
||||||
Next, the handler `app_activate` is now very simple.
|
Next, the handler `app_activate` is added and is very simple.
|
||||||
It just outputs the error message.
|
It just outputs the error message and
|
||||||
The application quits immediately because no window is created.
|
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.
|
- Creates GtkApplicationWindow, GtkScrolledWindow, GtkTextView and GtkTextBuffer and connects them together;
|
||||||
- Sets wrap mode to `GTK_WRAP_WORD_CHAR` in GtktextView.
|
- 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.
|
- 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).
|
- 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. It makes the application quit.
|
- 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
|
~~~C
|
||||||
if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
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.
|
The function `g_file_load_contents` loads the file contents into a buffer,
|
||||||
And the length of the buffer is set to `length`.
|
which is automatically allocated and sets `contents` to point that buffer.
|
||||||
It returns `TRUE` if the file's contents are successfully loaded. `FALSE` if an error happens.
|
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,
|
If this function succeeds, it inserts the contents into GtkTextBuffer,
|
||||||
frees the memories pointed by `filename` and shows the window.
|
frees the buffer pointed by `contents`, sets the title of the window,
|
||||||
If it fails, it outputs an error message and destroys 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
|
||||||
|
|
||||||
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)
|
![GtkNotebook](../image/screenshot_gtk_notebook.png)
|
||||||
|
|
||||||
Look at the screenshots above.
|
Looking at the screenshots above,
|
||||||
The left one is a window at the startup.
|
the left one is the window at the startup.
|
||||||
It shows the file `pr1.c`.
|
It shows the file `pr1.c` and the filename is in the left tab.
|
||||||
The filename is in the left tab.
|
After clicking on the right tab, the contents of the file `tfv1.c` are shown instead.
|
||||||
After clicking on the right tab, the contents of `tfv1.c` appears.
|
This is shown in the right screenshot.
|
||||||
It is shown in the right of the screenshot.
|
|
||||||
|
|
||||||
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
|
The GtkNotebook widget is inserted as a child of GtkApplicationWindow and contains a GtkScrolledWindow
|
||||||
Now I want to show you the program `tfv4.c`.
|
for each file that is being displayed.
|
||||||
|
The code to do this is given in `tfv4.c` and is:
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
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);
|
66 app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
|
||||||
67 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
67 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
68 g_signal_connect (app, "open", G_CALLBACK (app_open), 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);
|
70 g_object_unref (app);
|
||||||
71 return stat;
|
71 return stat;
|
||||||
72 }
|
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.
|
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".
|
- 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.
|
- 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.
|
- 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.
|
- 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 is get from the GtkTextView.
|
- 32-37 GtkScrollledWindow, GtkTextView are created and GtkTextBuffer found from the new GtkTextView.
|
||||||
GtkTextView is connected to GtkScrolledWindow as a child.
|
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`.
|
- 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.
|
- 41-43: Gets the filename and creates GtkLabel with the filename and then frees `filename`.
|
||||||
Frees `filename`.
|
|
||||||
- 44-45: If `filename` is NULL, creates GtkLabel with the empty string.
|
- 44-45: If `filename` is NULL, creates GtkLabel with the empty string.
|
||||||
- 46: Appends GtkScrolledWindow and GtkLabel to GtkNotebook.
|
- 46: Appends GtkScrolledWindow as a page, with the tab GtkLabel, to GtkNotebook.
|
||||||
At the same time, a GtkNoteBookPage widget is created automatically.
|
At this time a GtkNoteBookPage widget is created automatically.
|
||||||
The GtkScrolledWindow widget is connected to the GtkNotebookPage.
|
The GtkScrolledWindow widget is connected to the GtkNotebookPage.
|
||||||
Therefore, the structure is like this:
|
Therefore, the structure is like this:
|
||||||
|
|
||||||
|
@ -332,18 +330,16 @@ Therefore, the structure is like this:
|
||||||
GtkNotebook -- GtkNotebookPage -- GtkScrolledWindow
|
GtkNotebook -- GtkNotebookPage -- GtkScrolledWindow
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
- 47: Gets GtkNotebookPage widget and sets `nbp` to point the GtkNotebookPage.
|
- 47: Gets GtkNotebookPage widget and sets `nbp` to point to this GtkNotebookPage.
|
||||||
- 48: GtkNotebookPage has a property "tab-expand".
|
- 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 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.
|
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).
|
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.
|
- 49-51: If the file cannot be read, "No such file" message is displayed and the `filename` buffer is freed.
|
||||||
Frees `filename`.
|
- 52-53: If `filename` is NULL, the "No valid file is given" message is outputted.
|
||||||
- 52-53: If `filename` is NULL, "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.
|
- 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 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)
|
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
|
# String and memory management
|
||||||
|
|
||||||
GtkTextView and GtkTextBuffer have functions that have string parameters or return a string.
|
GtkTextView and GtkTextBuffer have functions that use string parameters or return a string.
|
||||||
The knowledge of strings and memory management is very important for us to understand the functions above.
|
The knowledge of strings and memory management is useful to understand how to use these functions.
|
||||||
|
|
||||||
## String and memory
|
## String and memory
|
||||||
|
|
||||||
String is an array of characters that is terminated with '\0'.
|
A String is an array of characters that is terminated with '\0'.
|
||||||
String is not a C type such as char, int, float or double.
|
Strings are 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.
|
but exist as a pointer to a character array. They behaves like a string type
|
||||||
So, the pointer is often called string.
|
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
|
~~~C
|
||||||
char a[10], *b;
|
char a[10], *b;
|
||||||
|
@ -25,46 +28,50 @@ b = a;
|
||||||
/* *(++b) is 'e' */
|
/* *(++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'.
|
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 first five elements are character codes that correspond to the characters.
|
||||||
The sixth element is '\0' that is the same as zero.
|
The sixth element is '\0', which is the same as zero,
|
||||||
And it indicates that the string ends there.
|
and indicates that the string ends there.
|
||||||
The size of the array is 10, so 4 bytes aren't used, but it's OK.
|
The size of the array is 10, so 4 bytes aren't used, but that's OK,
|
||||||
They are just ignored.
|
they are just ignored.
|
||||||
|
|
||||||
The variable 'b' is a pointer to a character.
|
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.
|
The variable `a` is defined as an array and it can't be changed.
|
||||||
It always point the top address of the array.
|
It always point the top address of the array.
|
||||||
On the other hand, pointers are mutable, so `b` can change itself.
|
On the other hand, 'b' is a pointer, which is mutable, so `b` can be change.
|
||||||
It is possible to write `++b` (`b` is increased by one).
|
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.
|
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.
|
Another annoying problem is the memory that a string is allocated.
|
||||||
There are four cases.
|
There are four cases:
|
||||||
|
|
||||||
- The string is read only.
|
- The string is read only;
|
||||||
- The string is in static memory area.
|
- The string is in static memory area;
|
||||||
- The string is in stack.
|
- The string is in stack; and
|
||||||
- The string is in memory allocated from the heap area.
|
- The string is in memory allocated from the heap area.
|
||||||
|
|
||||||
## Read only string
|
## 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
|
~~~C
|
||||||
char *s;
|
char *s;
|
||||||
s = "Hello"
|
s = "Hello"
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
"Hello" is a string literal.
|
"Hello" is a string literal, and is stored in program memory.
|
||||||
A string literal is read only.
|
A string literal is read only.
|
||||||
In the program above, `s` points the string literal.
|
In the program above, `s` points the string literal.
|
||||||
|
|
||||||
So, the following program is illegal.
|
So, the following program is illegal.
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
|
@ -74,18 +81,22 @@ So, the following program is illegal.
|
||||||
The result is undefined.
|
The result is undefined.
|
||||||
Probably a bad thing will happen, for example, a segmentation fault.
|
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
|
## Strings defined as arrays
|
||||||
|
|
||||||
If a string is defined as an array, it's in static memory area or stack.
|
If a string is defined as an array, it's in either stored in the static memory area or stack.
|
||||||
It depends on the class of the array.
|
This depends on the class of the array.
|
||||||
If the array's class is `static`, then it's placed in static memory area.
|
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 allocation and memory address is fixed for the life of the program.
|
||||||
This area is writable.
|
This area can be changed and is writable.
|
||||||
|
|
||||||
If the array's class is `auto`, then it's placed in stack.
|
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`.
|
If the array is defined inside a function, its default class is `auto`.
|
||||||
The stack area will disappear when the function returns to the caller.
|
The stack area will disappear when the function exits and returns to the caller.
|
||||||
stack is writable.
|
Arrays defined on the stack are writable.
|
||||||
|
|
||||||
~~~C
|
~~~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.
|
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.
|
The compiler calculates the number of the elements in the right hand side (six),
|
||||||
It is six.
|
and then creates code that allocates six bytes in the static memory area and copies the data to this memory.
|
||||||
The compiler allocates six bytes memory in the static memory area and copies the data to the memory.
|
|
||||||
|
|
||||||
The array `b` is defined inside the function.
|
The array `b` is defined inside the function
|
||||||
So, its class is `auto`.
|
so its class is `auto`.
|
||||||
The compiler calculates the number of the elements in the string literal.
|
The compiler calculates the number of the elements in the string literal.
|
||||||
It is six because the string is zero terminated.
|
It has six elements as the zero termination character is also included.
|
||||||
The compiler allocates six bytes memory in the stack and copies the data to the memory.
|
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.
|
Both `a` and `b` are writable.
|
||||||
|
|
||||||
The memory is managed by the executable program.
|
The memory is managed by the executable program.
|
||||||
You don't need to program to allocate or free the memory for `a` and `b`.
|
You don't need your program to allocate or free the memory for `a` and `b`.
|
||||||
The array `a` remains for the life of the program.
|
The array `a` is created then the program is first run and remains for the life of the program.
|
||||||
The array `b` disappears when the function returns to the caller.
|
The array `b` is created on the stack then the function is called, disappears when the function returns.
|
||||||
|
|
||||||
## Strings in the heap area
|
## 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.
|
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
|
~~~C
|
||||||
g_new (struct_type, n_struct)
|
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.
|
`gpointer` is a type of general pointer.
|
||||||
It is the same as `void *`.
|
It is the same as `void *`.
|
||||||
This pointer can be casted to any pointer type.
|
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
|
~~~C
|
||||||
g_free (s);
|
g_free (s);
|
||||||
|
@ -173,10 +184,10 @@ g_free (t);
|
||||||
/* Frees the memory allocated to 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.
|
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
|
~~~C
|
||||||
char *s;
|
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 returned string should be freed with `g_free()` when no longer needed.
|
||||||
|
|
||||||
The reference usually describes if the returned value needs to be freed.
|
The function reference will describe if the returned value needs to be freed.
|
||||||
If you forget to free the allocated memory, it causes memory leak.
|
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.
|
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.
|
This function returns `const char*` type.
|
||||||
The qualifier `const` means immutable.
|
The qualifier `const` means that the returned value is immutable.
|
||||||
Therefore, the characters pointed by the returned value aren't be allowed to change or free.
|
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
|
~~~C
|
||||||
const int x = 10; /* initialization is OK. */
|
const int x = 10; /* initialization is OK. */
|
||||||
|
|
||||||
x = 20; /* This is illegal because x is qualified with const */
|
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
|
### G\_APPLICATION\_HANDLES\_OPEN flag
|
||||||
|
|
||||||
GtkTextView, GtkTextBuffer and GtkScrolledWindow have given us a minimum editor in the previous section.
|
The GtkTextView, GtkTextBuffer and GtkScrolledWindow widgets have given us a minimum editor
|
||||||
Next, we will add a function to read a file and remake the program into a file viewer.
|
in the previous section.
|
||||||
There are many ways to implement the function.
|
We will now add a function to read a file and rework the program into a file viewer.
|
||||||
Because this is a tutorial for beginners, we'll take the easiest one.
|
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
|
$ ./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.
|
To do this, 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).
|
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
|
~~~C
|
||||||
GtkApplication *
|
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`.
|
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.
|
If you want to handle command line arguments, the `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).
|
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).
|
and the flag is described in the [GIO API Reference, ApplicationFlags](https://docs.gtk.org/gio/flags.ApplicationFlags.html).
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
GApplicationFlags' Members
|
GApplicationFlags' Members
|
||||||
|
@ -39,18 +40,15 @@ G_APPLICATION_HANDLES_OPEN This application handles opening files (in the prima
|
||||||
... ... ...
|
... ... ...
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
There are ten flags.
|
There are ten flags in total, but we only need two of them so far.
|
||||||
But we only need two of them so far.
|
We've already used `G_APPLICATION_FLAGS_NONE`, as
|
||||||
We've already used `G_APPLICATION_FLAGS_NONE`.
|
it is the simplest option, and no arguments are allowed.
|
||||||
It is the simplest option.
|
If you provide arguments when running the application, an error will occur.
|
||||||
No argument is allowed.
|
|
||||||
If you give arguments and run the application, then error occurs.
|
|
||||||
|
|
||||||
`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.
|
It allows arguments but only files.
|
||||||
The application assumes all the arguments are filenames.
|
The application assumes all the arguments are filenames and we will use this flag when creating
|
||||||
|
our GtkApplication.
|
||||||
Now we use this flag when creating GtkApplication.
|
|
||||||
|
|
||||||
~~~C
|
~~~C
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
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
|
### 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.
|
- activate signal --- This signal is emitted when there's no argument.
|
||||||
- open signal --- This signal is emitted when there is at least one 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
|
~~~C
|
||||||
void user_function (GApplication *application,
|
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)
|
- `hint` --- a hint provided by the calling instance (usually it can be ignored)
|
||||||
- `user_data` --- user data set when the signal handler was connected.
|
- `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
|
## Making a file viewer
|
||||||
|
|
||||||
### What is a file viewer?
|
### What is a file viewer?
|
||||||
|
|
||||||
A file viewer is a program that shows a text file given as an argument.
|
A file viewer is a program that displays the text file that is given as an argument.
|
||||||
It works as follows.
|
Our file viewer will work as follows.
|
||||||
|
|
||||||
- If it is given arguments, it recognizes the first argument as a filename and opens it.
|
- 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 shows the window.
|
- 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, shows an error message and quits.
|
- If it fails to open the file, it will show an error message and quit.
|
||||||
- If there's no argument, it shows an error message and quits.
|
- If there's no argument, it will shows an error message and quit.
|
||||||
- If there are two or more arguments, the second one and after are ignored.
|
- 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
|
@@@include
|
||||||
tfv/tfv3.c
|
tfv/tfv3.c
|
||||||
|
@ -110,25 +108,25 @@ Then compile and run it.
|
||||||
|
|
||||||
![File viewer](../image/screenshot_tfv3.png){width=6.3cm height=5.325cm}
|
![File viewer](../image/screenshot_tfv3.png){width=6.3cm height=5.325cm}
|
||||||
|
|
||||||
Now I want to explain the program `tfv3.c`.
|
Let's explain how the program `tfv3.c` works.
|
||||||
First, the function `main` changes in only two lines from the previous version.
|
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.
|
- `g_signal_connect (app, "open", G_CALLBACK (on_open), NULL)` is added.
|
||||||
|
|
||||||
Next, the handler `app_activate` is now very simple.
|
Next, the handler `app_activate` is added and is very simple.
|
||||||
It just outputs the error message.
|
It just outputs the error message and
|
||||||
The application quits immediately because no window is created.
|
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.
|
- Creates GtkApplicationWindow, GtkScrolledWindow, GtkTextView and GtkTextBuffer and connects them together;
|
||||||
- Sets wrap mode to `GTK_WRAP_WORD_CHAR` in GtktextView.
|
- 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.
|
- 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).
|
- 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. It makes the application quit.
|
- 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
|
~~~C
|
||||||
if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
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.
|
The function `g_file_load_contents` loads the file contents into a buffer,
|
||||||
And the length of the buffer is set to `length`.
|
which is automatically allocated and sets `contents` to point that buffer.
|
||||||
It returns `TRUE` if the file's contents are successfully loaded. `FALSE` if an error happens.
|
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,
|
If this function succeeds, it inserts the contents into GtkTextBuffer,
|
||||||
frees the memories pointed by `filename` and shows the window.
|
frees the buffer pointed by `contents`, sets the title of the window,
|
||||||
If it fails, it outputs an error message and destroys 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
|
||||||
|
|
||||||
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}
|
![GtkNotebook](../image/screenshot_gtk_notebook.png){width=13.2cm height=5.325cm}
|
||||||
|
|
||||||
Look at the screenshots above.
|
Looking at the screenshots above,
|
||||||
The left one is a window at the startup.
|
the left one is the window at the startup.
|
||||||
It shows the file `pr1.c`.
|
It shows the file `pr1.c` and the filename is in the left tab.
|
||||||
The filename is in the left tab.
|
After clicking on the right tab, the contents of the file `tfv1.c` are shown instead.
|
||||||
After clicking on the right tab, the contents of `tfv1.c` appears.
|
This is shown in the right screenshot.
|
||||||
It is shown in the right of the screenshot.
|
|
||||||
|
|
||||||
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
|
The GtkNotebook widget is inserted as a child of GtkApplicationWindow and contains a GtkScrolledWindow
|
||||||
Now I want to show you the program `tfv4.c`.
|
for each file that is being displayed.
|
||||||
|
The code to do this is given in `tfv4.c` and is:
|
||||||
|
|
||||||
@@@include
|
@@@include
|
||||||
tfv/tfv4.c
|
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.
|
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".
|
- 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.
|
- 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.
|
- 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.
|
- 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 is get from the GtkTextView.
|
- 32-37 GtkScrollledWindow, GtkTextView are created and GtkTextBuffer found from the new GtkTextView.
|
||||||
GtkTextView is connected to GtkScrolledWindow as a child.
|
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`.
|
- 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.
|
- 41-43: Gets the filename and creates GtkLabel with the filename and then frees `filename`.
|
||||||
Frees `filename`.
|
|
||||||
- 44-45: If `filename` is NULL, creates GtkLabel with the empty string.
|
- 44-45: If `filename` is NULL, creates GtkLabel with the empty string.
|
||||||
- 46: Appends GtkScrolledWindow and GtkLabel to GtkNotebook.
|
- 46: Appends GtkScrolledWindow as a page, with the tab GtkLabel, to GtkNotebook.
|
||||||
At the same time, a GtkNoteBookPage widget is created automatically.
|
At this time a GtkNoteBookPage widget is created automatically.
|
||||||
The GtkScrolledWindow widget is connected to the GtkNotebookPage.
|
The GtkScrolledWindow widget is connected to the GtkNotebookPage.
|
||||||
Therefore, the structure is like this:
|
Therefore, the structure is like this:
|
||||||
|
|
||||||
|
@ -200,16 +200,14 @@ Therefore, the structure is like this:
|
||||||
GtkNotebook -- GtkNotebookPage -- GtkScrolledWindow
|
GtkNotebook -- GtkNotebookPage -- GtkScrolledWindow
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
- 47: Gets GtkNotebookPage widget and sets `nbp` to point the GtkNotebookPage.
|
- 47: Gets GtkNotebookPage widget and sets `nbp` to point to this GtkNotebookPage.
|
||||||
- 48: GtkNotebookPage has a property "tab-expand".
|
- 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 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.
|
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).
|
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.
|
- 49-51: If the file cannot be read, "No such file" message is displayed and the `filename` buffer is freed.
|
||||||
Frees `filename`.
|
- 52-53: If `filename` is NULL, the "No valid file is given" message is outputted.
|
||||||
- 52-53: If `filename` is NULL, "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.
|
- 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 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;
|
gchar *text;
|
||||||
|
|
||||||
text =
|
text =
|
||||||
"Once upon a time, there was an old man who was called Taketori-no-Okina. "
|
"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"
|
"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. "
|
"One day, he went into a mountain and found a shining bamboo. "
|
||||||
"\"What a mysterious bamboo it is!,\" he said. "
|
"\"What a mysterious bamboo it is!,\" he said. "
|
||||||
"He cut it, then there was a small cute baby girl in it. "
|
"He cut it, then there was a small cute baby girl in it. "
|
||||||
"The girl was shining faintly. "
|
"The girl was shining faintly. "
|
||||||
"He thought this baby girl is a gift from Heaven and took her home.\n"
|
"He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||||
"His wife was surprized at his tale. "
|
"His wife was surprized at his tale. "
|
||||||
"They were very happy because they had no children. "
|
"They were very happy because they had no children. "
|
||||||
;
|
;
|
||||||
win = gtk_application_window_new (GTK_APPLICATION (app));
|
win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||||
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
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);
|
app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
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);
|
g_object_unref (app);
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,16 @@ app_activate (GApplication *app, gpointer user_data) {
|
||||||
gchar *text;
|
gchar *text;
|
||||||
|
|
||||||
text =
|
text =
|
||||||
"Once upon a time, there was an old man who was called Taketori-no-Okina. "
|
"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"
|
"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. "
|
"One day, he went into a mountain and found a shining bamboo. "
|
||||||
"\"What a mysterious bamboo it is!,\" he said. "
|
"\"What a mysterious bamboo it is!,\" he said. "
|
||||||
"He cut it, then there was a small cute baby girl in it. "
|
"He cut it, then there was a small cute baby girl in it. "
|
||||||
"The girl was shining faintly. "
|
"The girl was shining faintly. "
|
||||||
"He thought this baby girl is a gift from Heaven and took her home.\n"
|
"He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||||
"His wife was surprized at his tale. "
|
"His wife was surprized at his tale. "
|
||||||
"They were very happy because they had no children. "
|
"They were very happy because they had no children. "
|
||||||
;
|
;
|
||||||
win = gtk_application_window_new (GTK_APPLICATION (app));
|
win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||||
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
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);
|
app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
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);
|
g_object_unref (app);
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,7 @@ main (int argc, char **argv) {
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
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, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
g_signal_connect (app, "open", G_CALLBACK (app_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,7 @@ main (int argc, char **argv) {
|
||||||
app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
|
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, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
g_signal_connect (app, "open", G_CALLBACK (app_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