Merge pull request #19 from PaulSchulz/main

Some more changes for readabilty.
This commit is contained in:
ToshioCP 2022-03-05 10:32:17 +09:00 committed by GitHub
commit 1d4741bdb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 332 additions and 314 deletions

View file

@ -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 }

View file

@ -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)

View file

@ -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)

View file

@ -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 */
~~~

View file

@ -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.

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}