2021-01-13 05:29:35 +01:00
|
|
|
# GtkApplication and GtkApplicationWindow
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
## GtkApplication
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
### GtkApplication and g\_application\_run
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
People write programming code to make an application.
|
2021-02-06 09:26:57 +01:00
|
|
|
What are applications?
|
2022-03-03 07:06:00 +01:00
|
|
|
Applications are software that runs using libraries, which includes the
|
|
|
|
OS, frameworks and so on.
|
2022-11-21 14:48:20 +01:00
|
|
|
In GTK 4 programming, the GtkApplication is a program (or executable) that runs
|
2022-03-03 07:06:00 +01:00
|
|
|
using Gtk libraries.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2022-03-03 07:06:00 +01:00
|
|
|
The basic way to write a GtkApplication is as follows.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2022-03-03 07:06:00 +01:00
|
|
|
- Create a GtkApplication instance.
|
|
|
|
- Run the application.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
That's all.
|
|
|
|
Very simple.
|
|
|
|
The following is the C code representing the scenario above.
|
|
|
|
|
2021-02-08 14:24:54 +01:00
|
|
|
@@@include
|
|
|
|
misc/pr1.c
|
|
|
|
@@@
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
The first line says that this program includes the header files of the Gtk libraries.
|
2022-12-21 14:31:33 +01:00
|
|
|
The function `main` is a startup function in C language.
|
2021-06-13 14:31:15 +02:00
|
|
|
The variable `app` is defined as a pointer to a GtkApplication instance.
|
|
|
|
The function `gtk_application_new` creates a GtkApplication instance and returns a pointer to the instance.
|
|
|
|
The GtkApplication instance is a C structure data in which the information about the application is stored.
|
2021-01-13 05:29:35 +01:00
|
|
|
The meaning of the arguments will be explained later.
|
2021-06-13 14:31:15 +02:00
|
|
|
The function `g_application_run` runs an application that the instance defined.
|
|
|
|
(We often say that the function runs `app`.
|
|
|
|
Actually, `app` is not an application but a pointer to the instance of the application.
|
2021-01-13 05:29:35 +01:00
|
|
|
However, it is simple and short, and probably no confusion occurs.)
|
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
Here I used the word `instance`.
|
|
|
|
Instance, class and object are terminologies in Object Oriented Programming.
|
|
|
|
I use these words in the same way.
|
|
|
|
But, I will often use "object" instead of "instance" in this tutorial.
|
|
|
|
That means "object" and "instance" is the same.
|
|
|
|
Object is a bit ambiguous word.
|
|
|
|
In a broad sense, object has wider meaning than instance.
|
|
|
|
So, readers should be careful of the contexts to find the meaning of "object".
|
|
|
|
In many cases, object and instance are the same.
|
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
To compile this, the following command needs to be run.
|
2021-06-13 14:31:15 +02:00
|
|
|
The string `pr1.c` is the filename of the C source code above.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
$ gcc `pkg-config --cflags gtk4` pr1.c `pkg-config --libs gtk4`
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2022-03-03 07:25:49 +01:00
|
|
|
The C compiler gcc generates an executable file, `a.out`.
|
2021-01-13 05:29:35 +01:00
|
|
|
Let's run it.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
$ ./a.out
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
(a.out:13533): GLib-GIO-WARNING **: 15:30:17.449: Your application does not implement
|
|
|
|
g_application_activate() and has no handlers connected to the "activate" signal.
|
|
|
|
It should do one of these.
|
2022-03-03 07:06:00 +01:00
|
|
|
$
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2022-03-03 07:25:49 +01:00
|
|
|
Oh, it just produces an error message.
|
|
|
|
This error message means that the GtkApplication object ran, without a doubt.
|
|
|
|
Now, let's think about what this message means.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
### signal
|
|
|
|
|
|
|
|
The message tells us that:
|
|
|
|
|
2022-03-03 07:25:49 +01:00
|
|
|
1. The application GtkApplication doesn't implement `g_application_activate()`,
|
|
|
|
2. It has no handlers connected to the "activate" signal, and
|
|
|
|
3. You will need to solve at least one of these.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
These two causes of the error are related to signals.
|
2022-03-03 07:25:49 +01:00
|
|
|
So, I will explain that to you first.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2022-03-03 07:25:49 +01:00
|
|
|
A signal is emitted when something happens.
|
2021-06-13 14:31:15 +02:00
|
|
|
For example, a window is created, a window is destroyed and so on.
|
2022-12-21 14:31:33 +01:00
|
|
|
The signal "activate" is emitted when the application is activated.
|
|
|
|
(Activated is a bit different from started, but you can think the both are almost same so far.)
|
2022-03-03 07:25:49 +01:00
|
|
|
If the signal is connected to a function, which is called a signal handler or
|
|
|
|
simply handler, then the function is invoked when the signal emits.
|
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
The flow is like this:
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
1. Something happens.
|
|
|
|
2. If it's related to a certain signal, then the signal is emitted.
|
2022-12-21 14:31:33 +01:00
|
|
|
3. If the signal has been connected to a handler in advance, then the handler is invoked.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
Signals are defined in objects.
|
2022-03-03 07:25:49 +01:00
|
|
|
For example, the "activate" signal belongs to the GApplication object, which is
|
|
|
|
a parent object of GtkApplication object.
|
|
|
|
|
|
|
|
The GApplication object is a child object of the GObject object.
|
2021-01-13 05:29:35 +01:00
|
|
|
GObject is the top object in the hierarchy of all the objects.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
GObject -- GApplication -- GtkApplication
|
|
|
|
<---parent --->child
|
|
|
|
~~~
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
A child object inherits signals, functions, properties and so on from its parent object.
|
2022-03-03 07:25:49 +01:00
|
|
|
So, GtkApplication also has the "activate" signal.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
Now we can solve the problem in `pr1.c`.
|
2021-06-13 14:47:46 +02:00
|
|
|
We need to connect the "activate" signal to a handler.
|
2021-01-13 05:29:35 +01:00
|
|
|
We use a function `g_signal_connect` which connects a signal to a handler.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-02-08 14:24:54 +01:00
|
|
|
@@@include
|
|
|
|
misc/pr2.c
|
|
|
|
@@@
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
First, we define the handler `app_activate` which simply displays a message.
|
2022-12-21 14:31:33 +01:00
|
|
|
The function `g_print` is defined in GLib and it's like a printf in the C standard library.
|
2021-01-13 05:29:35 +01:00
|
|
|
In the function `main`, we add `g_signal_connect` before `g_application_run`.
|
|
|
|
The function `g_signal_connect` has four arguments.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
1. An instance to which the signal belongs.
|
2021-01-13 05:29:35 +01:00
|
|
|
2. The name of the signal.
|
|
|
|
3. A handler function (also called callback), which needs to be casted by `G_CALLBACK`.
|
|
|
|
4. Data to pass to the handler. If no data is necessary, NULL should be given.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
It is described in the [GObject API Reference](https://docs.gtk.org/gobject/func.signal_connect.html).
|
|
|
|
Correctly, `g_signal_connect` is a macro (not a C function).
|
|
|
|
|
|
|
|
~~~c
|
|
|
|
#define g_signal_connect (
|
|
|
|
instance,
|
|
|
|
detailed_signal,
|
|
|
|
c_handler,
|
|
|
|
data
|
|
|
|
)
|
|
|
|
~~~
|
|
|
|
|
2021-06-23 11:36:45 +02:00
|
|
|
You can find the description of each signal in the API reference manual.
|
2022-12-21 14:31:33 +01:00
|
|
|
For example, "activate" signal is in [GApplication section](https://docs.gtk.org/gio/signal.Application.activate.html) in the GIO API Reference.
|
|
|
|
|
|
|
|
~~~c
|
|
|
|
void
|
|
|
|
activate (
|
|
|
|
GApplication* self,
|
|
|
|
gpointer user_data
|
|
|
|
)
|
|
|
|
~~~
|
|
|
|
|
|
|
|
This is a declaration of the "activate" signal handler.
|
|
|
|
You can use any name instead of "activate" in the declaration above.
|
|
|
|
The parameters are:
|
|
|
|
|
|
|
|
- self is an instance to which the signal belongs.
|
|
|
|
- user\_data is a data defined in the fourth argument of the `g_signal_connect` function.
|
|
|
|
If it is NULL, then you can ignore and left out the second parameter.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-06-23 11:36:45 +02:00
|
|
|
API reference manual is very important.
|
2022-12-21 14:31:33 +01:00
|
|
|
You should see and understand it.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
Let's compile the source file above (`pr2.c`) and run it.
|
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
$ gcc `pkg-config --cflags gtk4` pr2.c `pkg-config --libs gtk4`
|
|
|
|
$ ./a.out
|
|
|
|
GtkApplication is activated.
|
|
|
|
$
|
2022-03-03 07:06:00 +01:00
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
OK, well done.
|
|
|
|
However, you may have noticed that it's painful to type such a long line to compile.
|
|
|
|
It is a good idea to use shell script to solve this problem.
|
2022-03-03 07:06:00 +01:00
|
|
|
Make a text file which contains the following line.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
gcc `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
Then, save it under the directory $HOME/bin, which is usually /home/(username)/bin.
|
|
|
|
(If your user name is James, then the directory is /home/james/bin).
|
|
|
|
And turn on the execute bit of the file.
|
2021-06-13 14:31:15 +02:00
|
|
|
If the filename is `comp`, do like this:
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
$ chmod 755 $HOME/bin/comp
|
|
|
|
$ ls -log $HOME/bin
|
|
|
|
... ... ...
|
|
|
|
-rwxr-xr-x 1 62 May 23 08:21 comp
|
|
|
|
... ... ...
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
If this is the first time that you make a $HOME/bin directory and save a file in it, then you need to logout and login again.
|
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
$ comp pr2
|
|
|
|
$ ./a.out
|
|
|
|
GtkApplication is activated.
|
2022-03-03 07:06:00 +01:00
|
|
|
$
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
## GtkWindow and GtkApplicationWindow
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
### GtkWindow
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
A message "GtkApplication is activated." was printed out in the previous subsection.
|
|
|
|
It was good in terms of a test of GtkApplication.
|
2021-06-13 14:31:15 +02:00
|
|
|
However, it is insufficient because Gtk is a framework for graphical user interface (GUI).
|
2021-01-13 05:29:35 +01:00
|
|
|
Now we go ahead with adding a window into this program.
|
|
|
|
What we need to do is:
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
1. Create a GtkWindow.
|
2021-01-13 05:29:35 +01:00
|
|
|
2. Connect it to GtkApplication.
|
|
|
|
3. Show the window.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:47:46 +02:00
|
|
|
Now rewrite the function `app_activate`.
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
#### Create a GtkWindow
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-02-08 14:24:54 +01:00
|
|
|
@@@include
|
2021-06-13 14:31:15 +02:00
|
|
|
misc/pr3.c app_activate
|
2021-02-08 14:24:54 +01:00
|
|
|
@@@
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-02-06 09:26:57 +01:00
|
|
|
Widget is an abstract concept that includes all the GUI interfaces such as windows, dialogs, buttons, multi-line text, containers and so on.
|
2021-01-13 05:29:35 +01:00
|
|
|
And GtkWidget is a base object from which all the GUI objects derive.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
parent <-----> child
|
|
|
|
GtkWidget -- GtkWindow
|
|
|
|
~~~
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
GtkWindow includes GtkWidget at the top of its object.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
![GtkWindow and GtkWidget](../image/window_widget.png){width=9.0cm height=6.0cm}
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
The function `gtk_window_new` is defined as follows.
|
|
|
|
|
2021-01-25 13:20:15 +01:00
|
|
|
~~~C
|
|
|
|
GtkWidget *
|
|
|
|
gtk_window_new (void);
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
By this definition, it returns a pointer to GtkWidget, not GtkWindow.
|
2021-06-13 14:31:15 +02:00
|
|
|
It actually creates a new GtkWindow instance (not GtkWidget) but returns a pointer to GtkWidget.
|
2021-01-13 05:29:35 +01:00
|
|
|
However,the pointer points the GtkWidget and at the same time it also points GtkWindow that contains GtkWidget in it.
|
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
If you want to use `win` as a pointer to a GtkWindow type instance, you need to cast it.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-01-25 13:20:15 +01:00
|
|
|
~~~C
|
|
|
|
(GtkWindow *) win
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
It works, but isn't usually used.
|
|
|
|
Instead, `GTK_WINDOW` macro is used.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-01-25 13:20:15 +01:00
|
|
|
~~~C
|
|
|
|
GTK_WINDOW (win)
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
The macro is recommended because it does not only cast but also check the type.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
#### Connect it to GtkApplication.
|
|
|
|
|
2021-01-26 14:36:17 +01:00
|
|
|
The function `gtk_window_set_application` is used to connect GtkWindow to GtkApplication.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-01-25 13:20:15 +01:00
|
|
|
~~~C
|
|
|
|
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
|
|
|
~~~
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
You need to cast `win` to GtkWindow and `app` to GtkApplication with `GTK_WINDOW` and `GTK_APPLICATION` macro.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
GtkApplication continues to run until the related window is destroyed.
|
2021-06-13 14:31:15 +02:00
|
|
|
If you didn't connect GtkWindow and GtkApplication, GtkApplication destroys itself immediately.
|
|
|
|
Because no window is connected to GtkApplication, GtkApplication doesn't need to wait anything.
|
|
|
|
As it destroys itself, the GtkWindow is also destroyed.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
|
|
|
#### Show the window.
|
|
|
|
|
2023-01-03 07:30:06 +01:00
|
|
|
The function `gtk_window_present` presents the window to a user (shows it to the user).
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2023-01-03 07:30:06 +01:00
|
|
|
GTK 4 changes the default widget visibility to on, so every widget doesn't need to change it to on.
|
2021-01-13 05:29:35 +01:00
|
|
|
But, there's an exception.
|
2023-01-03 07:30:06 +01:00
|
|
|
Top level window (this term will be explained later) isn't visible when it is created.
|
2021-06-13 14:31:15 +02:00
|
|
|
So you need to use the function above to show the window.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2023-01-03 07:30:06 +01:00
|
|
|
You can use `gtk_widget_set_visible (win, true)` instead of `gtk_window_present`.
|
|
|
|
But the behavior of these two is different.
|
|
|
|
Suppose there are two windows win1 and win2 on the screen and win1 is behind win2.
|
|
|
|
Both windows are visible.
|
|
|
|
The function `gtk_widget_set_visible (win1, true)` does nothing because win1 is already visible.
|
|
|
|
So, win1 is still behind win2.
|
|
|
|
The other function `gtk_window_present (win1)` moves win1 to the top of the stack of the windows.
|
|
|
|
Therefore, if you want to present the window, you should use `gtk_window_present`.
|
|
|
|
|
|
|
|
Two functions `gtk_widget_show` and `gtk_widget_hide` is deprecated since GTK 4.10.
|
|
|
|
You should use `gtk_widget_set_visible` instead.
|
|
|
|
|
2022-12-21 14:31:33 +01:00
|
|
|
Save the program as `pr3.c`, then compile and run it.
|
2021-01-13 05:29:35 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
~~~
|
|
|
|
$ comp pr3
|
|
|
|
$ ./a.out
|
|
|
|
~~~
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
A small window appears.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
![Screenshot of the window](../image/screenshot_pr3.png){width=3.3cm height=3.825cm}
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
Click on the close button then the window disappears and the program finishes.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
### GtkApplicationWindow
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
GtkApplicationWindow is a child object of GtkWindow.
|
2022-12-21 14:31:33 +01:00
|
|
|
It has some extra feature for better integration with GtkApplication.
|
|
|
|
It is recommended to use it as the top-level window of the application instead of GtkWindow.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2022-05-01 16:05:05 +02:00
|
|
|
Now rewrite the program and use GtkApplicationWindow.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-02-08 14:24:54 +01:00
|
|
|
@@@include
|
2021-06-13 14:31:15 +02:00
|
|
|
misc/pr4.c app_activate
|
2021-02-08 14:24:54 +01:00
|
|
|
@@@
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-06-13 14:31:15 +02:00
|
|
|
When you create GtkApplicationWindow, you need to give GtkApplication instance as an argument.
|
|
|
|
Then it automatically connect these two instances.
|
2021-01-13 05:29:35 +01:00
|
|
|
So you don't need to call `gtk_window_set_application` any more.
|
2020-12-22 03:30:06 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
The program sets the title and the default size of the window.
|
|
|
|
Compile it and run `a.out`, then you will see a bigger window with its title "pr4".
|
2020-12-21 13:12:05 +01:00
|
|
|
|
2021-01-13 05:29:35 +01:00
|
|
|
![Screenshot of the window](../image/screenshot_pr4.png){width=6.3cm height=5.325cm}
|