2022-11-21 14:48:20 +01:00
Up: [README.md ](../README.md ), Prev: [Section 17 ](sec17.md ), Next: [Section 19 ](sec19.md )
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
# Stateful action
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
Some actions have states.
2023-07-15 10:27:53 +02:00
The typical values of states are boolean or string.
2021-06-21 04:22:04 +02:00
However, other types of states are possible if you want.
2021-06-15 04:24:42 +02:00
Actions which have states are called stateful.
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
## Stateful action without a parameter
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
Some menus are called toggle menu.
For example, fullscreen menu has a state which has two values -- fullscreen and non-fullscreen.
The value of the state is changed every time the menu is clicked.
An action corresponds to the fullscreen menu also have a state.
Its value is TRUE or FALSE and it is called boolean value.
TRUE corresponds to fullscreen and FALSE to non-fullscreen.
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
The following is an example code to implement a fullscreen menu except the signal handler.
2023-01-03 07:30:06 +01:00
The signal handler will be shown later.
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
~~~C
2023-01-03 07:30:06 +01:00
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
NULL, g_variant_new_boolean (FALSE));
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
... ... ...
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2021-06-21 04:22:04 +02:00
- `act_fullscreen` is a GSimpleAction instance.
It is created with `g_simple_action_new_stateful` .
2021-06-15 04:24:42 +02:00
The function has three arguments.
The first argument "fullscreen" is the name of the action.
The second argument is a parameter type.
`NULL` means the action doesn't have a parameter.
The third argument is the initial state of the action.
It is a GVariant value.
GVariant will be explained in the next subsection.
2023-07-15 10:27:53 +02:00
The function `g_variant_new_boolean (FALSE)` returns a boolean type GVariant value which is `FALSE` .
2023-01-03 07:30:06 +01:00
If there are two or more top level windows, each window has its own `act_fullscreen` action.
So, the number of the actions is the same as the number of the windows.
2023-07-15 10:27:53 +02:00
- The action `act_fullscreen` has "change-state" signal. The signal is connected to a handler `fullscreen_changed` .
2023-01-03 07:30:06 +01:00
If the fullscreen menu is clicked, then the corresponding action `act_fullscreen` is activated.
But no handler is connected to the "activate" signal.
Then, the default behavior for boolean-stated actions with a NULL parameter type like `act_fullscreen` is to toggle them via the “change-state” signal.
- The action is added to the GtkWindow `win` .
2023-07-15 10:27:53 +02:00
Therefore, the scope of the action is "win".
2021-06-21 04:22:04 +02:00
- `menu_item_fullscreen` is a GMenuItem instance.
2021-06-15 04:24:42 +02:00
There are two arguments.
2023-01-03 07:30:06 +01:00
The first argument "Full Screen" is the label of `menu_item_fullscreen` .
2021-06-21 04:22:04 +02:00
The second argument is an action.
The action "win.fullscreen" has a prefix "win" and an action name "fullscreen".
2021-06-15 04:24:42 +02:00
The prefix says that the action belongs to the window.
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
~~~C
2023-01-03 07:30:06 +01:00
1 static void
2 fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
3 if (g_variant_get_boolean (value))
4 gtk_window_maximize (win);
5 else
6 gtk_window_unmaximize (win);
7 g_simple_action_set_state (action, value);
8 }
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2023-01-03 07:30:06 +01:00
- The handler `fullscreen_changed` has three parameters.
2021-06-15 04:24:42 +02:00
The first parameter is the action which emits the "change-state" signal.
2021-06-21 04:22:04 +02:00
The second parameter is the value of the new state of the action.
2021-06-15 04:24:42 +02:00
The third parameter is a user data which is set in `g_signal_connect` .
2021-06-21 04:22:04 +02:00
- If the value is boolean type and `TRUE` , then it maximizes the window.
2023-07-15 10:27:53 +02:00
Otherwise it un-maximizes.
2021-06-21 04:22:04 +02:00
- Sets the state of the action with `value` .
2023-07-15 10:27:53 +02:00
Note: At this stage, that means the stage before `g_simple_action_set_state` is called, the state of the action still has the original value.
2021-06-21 04:22:04 +02:00
So, you need to set the state with the new value by `g_simple_action_set_state` .
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
You can use "activate" signal instead of "change-state" signal, or both signals.
2021-06-21 04:22:04 +02:00
But the way above is the simplest and the best.
2021-06-15 04:24:42 +02:00
### GVariant
2021-01-13 05:29:35 +01:00
2023-07-15 10:27:53 +02:00
GVariant is a fundamental type.
It isn't a child of GObject.
GVariant can contain boolean, string or other type values.
2021-06-15 04:24:42 +02:00
For example, the following program assigns TRUE to `value` whose type is GVariant.
2021-01-13 05:29:35 +01:00
2021-01-25 10:35:49 +01:00
~~~C
2021-06-15 04:24:42 +02:00
GVariant *value = g_variant_new_boolean (TRUE);
~~~
Another example is:
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
~~~C
GVariant *value2 = g_variant_new_string ("Hello");
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
`value2` is a GVariant and it has a string type value "Hello".
GVariant can contain other types like int16, int32, int64, double and so on.
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
If you want to get the original value, use g\_variant\_get series functions.
2023-01-03 07:30:06 +01:00
For example, you can get the boolean value with g\_variant_get_boolean.
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
~~~C
gboolean bool = g_variant_get_boolean (value);
~~~
2021-01-13 05:29:35 +01:00
2023-07-15 10:27:53 +02:00
Since `value` has been created as a boolean type GVariant with `TRUE` value, `bool` equals `TRUE` .
2021-06-15 04:24:42 +02:00
In the same way, you can get a string from `value2`
2021-01-13 05:29:35 +01:00
2021-01-25 10:35:49 +01:00
~~~C
2021-06-21 04:22:04 +02:00
const char *str = g_variant_get_string (value2, NULL);
2021-01-25 10:35:49 +01:00
~~~
2021-06-15 04:24:42 +02:00
The second parameter is a pointer to gsize type variable (gsize is defined as unsigned long).
2023-07-15 10:27:53 +02:00
If it isn't NULL, then the pointed value is used as the length by the function.
2021-06-15 04:24:42 +02:00
If it is NULL, nothing happens.
2023-07-15 10:27:53 +02:00
The returned string `str` is owned by the instance and can't be changed or freed by the caller.
2021-06-15 04:24:42 +02:00
## Stateful action with a parameter
Another example of stateful actions is an action corresponds to color select menus.
For example, there are three menus and each menu has red, green or blue color respectively.
2023-01-03 07:30:06 +01:00
They determine the background color of a GtkLabel widget.
2021-06-15 04:24:42 +02:00
One action is connected to the three menus.
2023-01-03 07:30:06 +01:00
The action has a state whose value is "red", "green" or "blue".
2021-06-15 04:24:42 +02:00
The values are string.
Those colors are given to the signal handler as a parameter.
2021-01-13 05:29:35 +01:00
2021-01-25 10:35:49 +01:00
~~~C
2023-01-03 07:30:06 +01:00
... ... ...
2023-07-15 10:27:53 +02:00
GVariantType *vtype = g_variant_type_new("s");
GSimpleAction *act_color
= g_simple_action_new_stateful ("color", vtype, g_variant_new_string ("red"));
g_variant_type_free (vtype);
2023-01-03 07:30:06 +01:00
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
... ... ...
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2023-07-15 10:27:53 +02:00
- GVariantType is a C structure and it keeps a type of GVariant.
It is created with the function `g_variant_type_new` .
The argument of the function is a GVariant type string.
So, `g_variant_type_new("s")` returns a GVariantType structure contains a string type.
The returned value, GVariantType structure, is owned by the caller.
So, you need to free it when it becomes useless.
- The variable `act_color` points a GSimpleAction instance.
2021-06-21 04:22:04 +02:00
It is created with `g_simple_action_new_stateful` .
2021-06-15 04:24:42 +02:00
The function has three arguments.
The first argument "color" is the name of the action.
The second argument is a parameter type which is GVariantType.
2021-06-21 04:22:04 +02:00
`g_variant_type_new("s")` creates GVariantType which is a string type (`G_VARIANT_TYPE_STRING`).
2021-06-15 04:24:42 +02:00
The third argument is the initial state of the action.
It is a GVariant.
The function `g_variant_new_string ("red")` returns a GVariant value which has the string value "red".
2023-07-15 10:27:53 +02:00
GVariant has a reference count and `g_variant_new_...` series functions returns a GVariant value with a floating reference.
That means the caller doesn't own the value at this point.
And `g_simple_action_new_stateful` function consumes the floating reference so you don't need to care about releasing the GVariant instance.
- The GVariantType structure `vtype` is useless after `g_simple_action_new_stateful` .
It is released with the function `g_variant_type_free` .
- The varable `menu_item_red` points a GMenuItem instance.
The function `g_menu_item_new` has two arguments.
2021-06-21 04:22:04 +02:00
The first argument "Red" is the label of `menu_item_red` .
2021-06-15 04:24:42 +02:00
The second argument is a detailed action.
2023-01-03 07:30:06 +01:00
Its prefix is "app", action name is "color" and target is "red".
2021-06-15 04:24:42 +02:00
Target is sent to the action as a parameter.
The same goes for `menu_item_green` and `menu_item_blue` .
2023-07-15 10:27:53 +02:00
- The function `g_signal_connect` connects the activate signal on the action `act_color` and the handler `color_activated` .
2021-06-21 04:22:04 +02:00
If one of the three menus is clicked, then the action `act_color` is activated with the target (parameter) which is given by the menu.
2021-06-15 04:24:42 +02:00
The following is the "activate" signal handler.
2021-01-13 05:29:35 +01:00
2021-01-25 10:35:49 +01:00
~~~C
2021-06-15 04:24:42 +02:00
static void
2023-01-03 07:30:06 +01:00
color_activated(GSimpleAction *action, GVariant *parameter) {
char *color = g_strdup_printf ("label.lb {background-color: %s;}",
2021-06-15 04:24:42 +02:00
g_variant_get_string (parameter, NULL));
gtk_css_provider_load_from_data (provider, color, -1);
g_free (color);
g_action_change_state (G_ACTION (action), parameter);
}
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2023-07-15 10:27:53 +02:00
- The handler originally has three parameters.
The third parameter is a user data set in the `g_signal_connect` function.
But it is left out because the fourth argument of the `g_signal_connect` has been NULL.
2021-06-15 04:24:42 +02:00
The first parameter is the action which emits the "activate" signal.
2023-07-15 10:27:53 +02:00
The second parameter is the parameter, or target, given to the action.
2021-06-15 04:24:42 +02:00
It is a color specified by the menu.
2023-07-15 10:27:53 +02:00
- The variable `color` is a CSS string created by `g_strdup_printf` .
The arguments of `g_strdup_printf` are the same as printf C standard function.
The function `g_variant_get_string` gets the string contained in `parameter` .
The string is owned by the instance and you mustn't change or free it.
The string `label.lb` is a selector.
It consists of `label` , a node name of GtkLabel, and `lb` which is a class name.
It selects GtkLabel which has `lb` class.
2023-01-03 07:30:06 +01:00
For example, menus have GtkLabel to display their labels, but they don't have `lb` class.
2023-07-15 10:27:53 +02:00
So, the CSS doesn't change their background color.
The string `{background-color %s}` makes the background color `%s` to which the color from `parameter` is assigned.
2021-06-15 04:24:42 +02:00
- Frees the string `color` .
2023-07-15 10:27:53 +02:00
- Changes the state with `g_action_change_state` .
2021-06-15 04:24:42 +02:00
2023-01-03 07:30:06 +01:00
Note: If you haven't set an "activate" signal handler, the signal is forwarded to "change-state" signal.
So, you can use "change-state" signal instead of "activate" signal.
See [`src/menu/menu2_change_state.c` ](../src/menu/menu2_change_state.c ).
2021-06-15 04:24:42 +02:00
### GVariantType
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
GVariantType gives a type of GVariant.
2023-07-15 10:27:53 +02:00
GVariantType is created with a type string.
2021-06-15 04:24:42 +02:00
- "b" means boolean type.
- "s" means string type.
The following program is a simple example.
2021-06-21 04:22:04 +02:00
It finally outputs the string "s".
2021-01-13 05:29:35 +01:00
2021-01-25 10:35:49 +01:00
~~~C
2021-06-15 04:24:42 +02:00
1 #include < glib.h >
2
3 int
4 main (int argc, char **argv) {
5 GVariantType *vtype = g_variant_type_new ("s");
2021-06-21 04:22:04 +02:00
6 const char *type_string = g_variant_type_peek_string (vtype);
2021-06-15 04:24:42 +02:00
7 g_print ("%s\n",type_string);
2023-07-15 10:27:53 +02:00
8 g_variant_type_free (vtype);
9 }
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2023-07-15 10:27:53 +02:00
- The function `g_variant_type_new` creates a GVariantType structure.
The argument "s" is a type string.
It means string.
The returned structure is owned by the caller.
When it becomes useless, you need to free it with the function `g_variant_type_free` .
- The function `g_variant_type_peek_string` takes a peek at `vtype` .
2021-06-21 04:22:04 +02:00
It is the string "s" given to `vtype` when it was created.
2023-07-15 10:27:53 +02:00
The string is owned by the instance and the caller can't change or free it.
- Prints the string to the terminal.
You can't free `vtype` before `g_print` because the string `type_string` is owned by `vtype` .
- Frees `vtype` .
2021-01-13 05:29:35 +01:00
2023-01-03 07:30:06 +01:00
## Example
2021-06-15 04:24:42 +02:00
The following code includes stateful actions above.
This program has menus like this:
![menu2 ](../image/menu2.png )
2021-01-13 05:29:35 +01:00
2021-06-15 04:24:42 +02:00
- Fullscreen menu toggles the size of the window between maximum and non-maximum.
If the window is maximum size, which is called full screen, then a check mark is put before "fullscreen" label.
2023-07-15 10:27:53 +02:00
- Red, green and blue menu determines the back ground color of the label in the window.
2021-06-21 04:22:04 +02:00
The menus have radio buttons on the left of the menus.
2021-06-15 04:24:42 +02:00
And the radio button of the selected menu turns on.
- Quit menu quits the application.
The code is as follows.
2021-01-13 05:29:35 +01:00
2021-01-25 10:35:49 +01:00
~~~C
1 #include < gtk / gtk . h >
2
2023-01-03 07:30:06 +01:00
3 /* The provider below provides application wide CSS data. */
4 GtkCssProvider *provider;
5
6 static void
7 fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
8 if (g_variant_get_boolean (value))
9 gtk_window_maximize (win);
10 else
11 gtk_window_unmaximize (win);
12 g_simple_action_set_state (action, value);
13 }
14
15 static void
16 color_activated(GSimpleAction *action, GVariant *parameter) {
17 char *color = g_strdup_printf ("label.lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
18 /* Change the CSS data in the provider. */
19 /* Previous data is thrown away. */
20 gtk_css_provider_load_from_data (provider, color, -1);
21 g_free (color);
22 g_action_change_state (G_ACTION (action), parameter);
23 }
24
25 static void
2023-07-15 10:27:53 +02:00
26 app_shutdown (GApplication *app, GtkCssProvider *provider) {
27 gtk_style_context_remove_provider_for_display (gdk_display_get_default(), GTK_STYLE_PROVIDER (provider));
28 }
29
30 static void
31 app_activate (GApplication *app) {
32 GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
33 gtk_window_set_title (win, "menu2");
34 gtk_window_set_default_size (win, 400, 300);
35
36 GtkWidget *lb = gtk_label_new (NULL);
37 gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
38 gtk_window_set_child (win, lb);
39
40 GSimpleAction *act_fullscreen
41 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
42 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
43 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
44
45 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
46
47 gtk_window_present (win);
48 }
2023-01-03 07:30:06 +01:00
49
2023-07-15 10:27:53 +02:00
50 static void
51 app_startup (GApplication *app) {
52 GVariantType *vtype = g_variant_type_new("s");
53 GSimpleAction *act_color
54 = g_simple_action_new_stateful ("color", vtype, g_variant_new_string ("red"));
55 g_variant_type_free (vtype);
56 GSimpleAction *act_quit
57 = g_simple_action_new ("quit", NULL);
58 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
59 g_signal_connect_swapped (act_quit, "activate", G_CALLBACK (g_application_quit), app);
60 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_color));
61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
62
63 GMenu *menubar = g_menu_new ();
64 GMenu *menu = g_menu_new ();
65 GMenu *section1 = g_menu_new ();
66 GMenu *section2 = g_menu_new ();
67 GMenu *section3 = g_menu_new ();
68 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
69 GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
70 GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
71 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
72 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
73
74 g_menu_append_item (section1, menu_item_fullscreen);
75 g_menu_append_item (section2, menu_item_red);
76 g_menu_append_item (section2, menu_item_green);
77 g_menu_append_item (section2, menu_item_blue);
78 g_menu_append_item (section3, menu_item_quit);
79 g_object_unref (menu_item_red);
80 g_object_unref (menu_item_green);
81 g_object_unref (menu_item_blue);
82 g_object_unref (menu_item_fullscreen);
83 g_object_unref (menu_item_quit);
84
85 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
86 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
87 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
88 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
89 g_object_unref (section1);
90 g_object_unref (section2);
91 g_object_unref (section3);
92 g_object_unref (menu);
93
94 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
95
96 provider = gtk_css_provider_new ();
97 /* Initialize the css data */
98 gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
99 /* Add CSS to the default GdkDisplay. */
100 gtk_style_context_add_provider_for_display (gdk_display_get_default (),
101 GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
102 g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), provider);
103 g_object_unref (provider); /* release provider, but it's still alive because the display owns it */
104 }
105
106 #define APPLICATION_ID "com.github.ToshioCP.menu2"
107
108 int
109 main (int argc, char **argv) {
110 GtkApplication *app;
111 int stat;
112
113 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
114 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
115 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
116
117 stat =g_application_run (G_APPLICATION (app), argc, argv);
118 g_object_unref (app);
119 return stat;
120 }
2023-01-03 07:30:06 +01:00
~~~
2023-07-15 10:27:53 +02:00
- 6-23: Action signal handlers.
- 25-28: The handler `app_shutdown` is called when the application quits.
It removes the provider from the display.
- 30-48: An activate signal handler.
- 32-34: A new window is created and assigned to `win` .
2023-01-03 07:30:06 +01:00
Its title and default size are set to "menu2" and 400x300 respectively.
2023-07-15 10:27:53 +02:00
- 36-38: A new label is created and assigned to `lb`
The label is given a CSS class "lb".
2023-01-03 07:30:06 +01:00
It is added to `win` as a child.
2023-07-15 10:27:53 +02:00
- 40-43: A toggle action is created and assigned to `act_fullscreen` .
2023-01-03 07:30:06 +01:00
It's connected to the signal handler `fullscreen_changed` .
2023-07-15 10:27:53 +02:00
It's added to the window, so the action scope is "win".
2023-01-03 07:30:06 +01:00
So, if there are two or more windows, the actions are created two or more.
2023-07-15 10:27:53 +02:00
- 45: The function `gtk_application_window_set_show_menubar` adds a menubar to the window.
- 47: Shows the window.
- 50-104: A startup signal handler.
- 52-61: Two actions `act_color` and `act_quit` are created.
2023-01-03 07:30:06 +01:00
These actions exists only one because the startup handler is called once.
They are connected to their handlers and added to the application.
Their scopes are "app".
2023-07-15 10:27:53 +02:00
- 63-92: Menus are built.
- 94: The menubar is added to the application.
- 96-103: A CSS provider is created with the CSS data and added to the default display.
The "shutdown" signal on the application is connected to a handler "app_shutdown".
2023-01-03 07:30:06 +01:00
So, the provider is removed from the display and freed when the application quits.
## Compile
Change your current directory to `src/menu` .
~~~
$ comp menu2
$./a.out
2021-01-25 10:35:49 +01:00
~~~
2021-01-13 05:29:35 +01:00
2023-01-03 07:30:06 +01:00
Then, you will see a window and the background color of the content is red.
2023-07-15 10:27:53 +02:00
You can change the size to maximum and change back to the original size.
2023-01-03 07:30:06 +01:00
You can change the background color to green or blue.
2021-01-25 10:35:49 +01:00
2023-07-15 10:27:53 +02:00
If you run the second application during the first application is running, another window will appear in the same screen.
2023-01-03 07:30:06 +01:00
Both of the window have the same background color.
Because the `act_color` action has "app" scope and the CSS is applied to the default display shared by the windows.
2021-01-25 10:35:49 +01:00
2023-07-15 10:27:53 +02:00
```
$ ./a.out & # Run the first application
[1] 82113
$ ./a.out # Run the second application
$
```
2022-11-21 14:48:20 +01:00
Up: [README.md ](../README.md ), Prev: [Section 17 ](sec17.md ), Next: [Section 19 ](sec19.md )