Update gfm files of the section 16-30.

This commit is contained in:
Toshio Sekiya 2023-01-18 14:37:14 +09:00
parent e0897922ce
commit c84cffd8ef
5 changed files with 961 additions and 875 deletions

View file

@ -3,29 +3,29 @@ Up: [README.md](../README.md), Prev: [Section 25](sec25.md), Next: [Section 27]
# GtkListView # GtkListView
GTK 4 has added new list objects GtkListView, GtkGridView and GtkColumnView. GTK 4 has added new list objects GtkListView, GtkGridView and GtkColumnView.
The new feature is described in [Gtk API Reference, List Widget Overview](https://docs.gtk.org/gtk4/section-list-widget.html). The new feature is described in [Gtk API Reference -- List Widget Overview](https://docs.gtk.org/gtk4/section-list-widget.html).
GTK 4 has other means to implement lists. GTK 4 has other means to implement lists.
They are GtkListBox and GtkTreeView which are took over from GTK 3. They are GtkListBox and GtkTreeView which are took over from GTK 3.
There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen. There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen.
He described why GtkListView are developed to replace GtkListBox and GtkTreeView. He described why GtkListView are developed to replace GtkListBox and GtkTreeView.
I want to explain GtkListView and its related objects in this tutorial. GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 26 to 29.
## Outline ## Outline
A list is a sequential data structure. A list is a sequential data structure.
For example, an ordered string sequence "one", "two", "three", "four" is a list. For example, an ordered string sequence "one", "two", "three", "four" is a list.
Each element of the list is called item. Each element is called item.
A list is like an array, but in many cases it is implemented with pointers which point to the next item of the list. A list is like an array, but in many cases it is implemented with pointers which point to the next items of the list.
And it has a start point. And it has a start point.
So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...). So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...).
There are two cases. There are two cases.
One is the index starts from one (one-based) and the other is it starts from zero (zero-based). One is the index starts from one (one-based) and the other is from zero (zero-based).
Gio provides GListModel interface. Gio provides GListModel interface.
It is a zero-based list of the same type of GObject objects, or objects that implement the same interface. It is a zero-based list of the same type of GObject descendants, or objects that implement the same interface.
An object implements GListModel is usually not a widget. An object implements GListModel is not a widget.
So, the list is not displayed on the screen directly. So, the list is not displayed on the screen directly.
There's another object GtkListView which is a widget to display the list. There's another object GtkListView which is a widget to display the list.
The items in the list need to be connected to the items in GtkListView. The items in the list need to be connected to the items in GtkListView.
@ -33,16 +33,11 @@ GtkListItemFactory object maps items in the list to GListView.
![List](../image/list.png) ![List](../image/list.png)
The instruction to build the whole list related objects is:
1. Implement the list object which implements GListModel.
2. Build widgets and put GtkListView as a child of GtkScrolledWindow.
3. Set GtkListItemFactory.
## GListModel ## GListModel
If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list. If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list.
Because GListModel is a list of GObject objects and strings aren't GObject objects. Because GListModel is a list of GObject objects and strings aren't GObject objects.
The word "GObject" here means "GObject class or its descendant class".
So, you need a wrapper which is a GObject and contains a string. So, you need a wrapper which is a GObject and contains a string.
GtkStringObject is the wrapper object and GStringList, implements GListModel, is a list of GtkStringObject. GtkStringObject is the wrapper object and GStringList, implements GListModel, is a list of GtkStringObject.
@ -51,7 +46,7 @@ char *array[] = {"one", "two", "three", "four", NULL};
GtkStringList *stringlist = gtk_string_list_new ((const char * const *) array); GtkStringList *stringlist = gtk_string_list_new ((const char * const *) array);
~~~ ~~~
The function `gtk_string_list_new` creates GtkStringList object. The function `gtk_string_list_new` creates a GtkStringList object.
Its items are GtkStringObject objects which contain the strings "one", "two", "three" and "four". Its items are GtkStringObject objects which contain the strings "one", "two", "three" and "four".
There are functions to add items to the list or remove items from the list. There are functions to add items to the list or remove items from the list.
@ -59,9 +54,9 @@ There are functions to add items to the list or remove items from the list.
- `gtk_string_list_remove` removes an item from the list - `gtk_string_list_remove` removes an item from the list
- `gtk_string_list_get_string` gets a string in the list - `gtk_string_list_get_string` gets a string in the list
See [GTK 4 API Reference, GtkStringList](https://docs.gtk.org/gtk4/class.StringList.html) for further information. See [GTK 4 API Reference -- GtkStringList](https://docs.gtk.org/gtk4/class.StringList.html) for further information.
I'll explain the other list objects later. Other list objects will be explained later.
## GtkSelectionModel ## GtkSelectionModel
@ -101,7 +96,7 @@ There are four signals.
1. "setup" is emitted to set up GtkListItem object. 1. "setup" is emitted to set up GtkListItem object.
A user sets its child widget in the handler. A user sets its child widget in the handler.
For example, creates a GtkLabel widget and sets the child property of GtkListItem to it. For example, creates a GtkLabel widget and sets the child property of GtkListItem with it.
This setting is kept even the GtkListItem instance is recycled (to bind to another item of GListModel). This setting is kept even the GtkListItem instance is recycled (to bind to another item of GListModel).
2. "bind" is emitted to bind an item in the list model to the widget. 2. "bind" is emitted to bind an item in the list model to the widget.
For example, a user gets the item from "item" property of the GtkListItem instance. For example, a user gets the item from "item" property of the GtkListItem instance.
@ -121,7 +116,7 @@ GtkNoSelection is used, so user can't select any item.
1 #include <gtk/gtk.h> 1 #include <gtk/gtk.h>
2 2
3 static void 3 static void
4 setup_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) { 4 setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
5 GtkWidget *lb = gtk_label_new (NULL); 5 GtkWidget *lb = gtk_label_new (NULL);
6 gtk_list_item_set_child (listitem, lb); 6 gtk_list_item_set_child (listitem, lb);
7 } 7 }
@ -129,38 +124,38 @@ GtkNoSelection is used, so user can't select any item.
9 static void 9 static void
10 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) { 10 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
11 GtkWidget *lb = gtk_list_item_get_child (listitem); 11 GtkWidget *lb = gtk_list_item_get_child (listitem);
12 GtkStringObject *strobj = gtk_list_item_get_item (listitem); 12 /* Strobj is owned by the instance. Caller mustn't change or destroy it. */
13 const char *text = gtk_string_object_get_string (strobj); 13 GtkStringObject *strobj = gtk_list_item_get_item (listitem);
14 14 const char *text = gtk_string_object_get_string (strobj);
15 gtk_label_set_text (GTK_LABEL (lb), text); 15
16 } 16 gtk_label_set_text (GTK_LABEL (lb), text);
17 17 }
18 static void 18
19 unbind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) { 19 static void
20 /* There's nothing to do here. */ 20 unbind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
21 /* If you does something like setting a signal in bind_cb, */ 21 /* There's nothing to do here. */
22 /* then disconnecting the signal is necessary in unbind_cb. */ 22 }
23 } 23
24 24 static void
25 static void 25 teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
26 teardown_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) { 26 gtk_list_item_set_child (listitem, NULL);
27 gtk_list_item_set_child (listitem, NULL); 27 /* The previous child is destroyed automatically. */
28 /* When the child of listitem is set to NULL, the reference to GtkLabel will be released and lb will be destroyed. */ 28 }
29 /* Therefore, g_object_unref () for the GtkLabel object doesn't need in the user code. */ 29
30 } 30 static void
31 31 app_activate (GApplication *application) {
32 /* ----- activate, open, startup handlers ----- */ 32 GtkApplication *app = GTK_APPLICATION (application);
33 static void 33 GtkWidget *win = gtk_application_window_new (app);
34 app_activate (GApplication *application) { 34 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
35 GtkApplication *app = GTK_APPLICATION (application); 35 GtkWidget *scr = gtk_scrolled_window_new ();
36 GtkWidget *win = gtk_application_window_new (app); 36 gtk_window_set_child (GTK_WINDOW (win), scr);
37 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400); 37
38 GtkWidget *scr = gtk_scrolled_window_new (); 38 char *array[] = {
39 gtk_window_set_child (GTK_WINDOW (win), scr); 39 "one", "two", "three", "four", NULL
40 40 };
41 char *array[] = { 41 /* sl is owned by ns */
42 "one", "two", "three", "four", NULL 42 /* ns and factory are owned by lv. */
43 }; 43 /* Therefore, you don't need to care about their destruction. */
44 GtkStringList *sl = gtk_string_list_new ((const char * const *) array); 44 GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
45 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (sl)); 45 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (sl));
46 46
@ -175,34 +170,26 @@ GtkNoSelection is used, so user can't select any item.
55 gtk_window_present (GTK_WINDOW (win)); 55 gtk_window_present (GTK_WINDOW (win));
56 } 56 }
57 57
58 static void 58 /* ----- main ----- */
59 app_startup (GApplication *application) { 59 #define APPLICATION_ID "com.github.ToshioCP.list1"
60 } 60
61 61 int
62 /* ----- main ----- */ 62 main (int argc, char **argv) {
63 #define APPLICATION_ID "com.github.ToshioCP.list1" 63 GtkApplication *app;
64 64 int stat;
65 int 65
66 main (int argc, char **argv) { 66 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
67 GtkApplication *app; 67
68 int stat; 68 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
69 69
70 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); 70 stat =g_application_run (G_APPLICATION (app), argc, argv);
71 71 g_object_unref (app);
72 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); 72 return stat;
73 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); 73 }
74
75 stat =g_application_run (G_APPLICATION (app), argc, argv);
76 g_object_unref (app);
77 return stat;
78 }
79
~~~ ~~~
The file `list1.c` is located under the directory [src/misc](../src/misc). The file `list1.c` is located under the directory [src/misc](../src/misc).
Make a shell script below and save it to your bin directory. Make a shell script below and save it to your bin directory, for example `$HOME/bin`.
(If you've installed GTK 4 from the source to $HOME/local, then your bin directory is $Home/local/bin.
Otherwise, $Home/bin is your private bin directory.)
~~~Shell ~~~Shell
gcc `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4` gcc `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
@ -211,16 +198,16 @@ gcc `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
Change the current directory to the directory includes `list1.c` and type as follows. Change the current directory to the directory includes `list1.c` and type as follows.
~~~ ~~~
$ chmod 755 $HOME/local/bin/comp # or chmod 755 $Home/bin/comp $ chmod 755 $HOME/bin/comp # or chmod 755 (your bin directory)/comp
$ comp list1 $ comp list1
$ ./a.out $ ./a.out
~~~ ~~~
Then, `list1.c` has been compiled and executed. Then, the following window appears.
![list1](../image/list1.png) ![list1](../image/list1.png)
I think the program is not so difficult. The program is not so difficult.
If you feel some difficulty, read this section again, especially GtkSignalListItemFactory subsubsection. If you feel some difficulty, read this section again, especially GtkSignalListItemFactory subsubsection.
### GtkBuilderListItemFactory ### GtkBuilderListItemFactory
@ -311,28 +298,23 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
38 gtk_window_present (GTK_WINDOW (win)); 38 gtk_window_present (GTK_WINDOW (win));
39 } 39 }
40 40
41 static void 41 /* ----- main ----- */
42 app_startup (GApplication *application) { 42 #define APPLICATION_ID "com.github.ToshioCP.list2"
43 } 43
44 44 int
45 /* ----- main ----- */ 45 main (int argc, char **argv) {
46 #define APPLICATION_ID "com.github.ToshioCP.list2" 46 GtkApplication *app;
47 47 int stat;
48 int 48
49 main (int argc, char **argv) { 49 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
50 GtkApplication *app; 50
51 int stat; 51 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
52 52
53 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); 53 stat =g_application_run (G_APPLICATION (app), argc, argv);
54 54 g_object_unref (app);
55 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); 55 return stat;
56 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); 56 }
57 57
58 stat =g_application_run (G_APPLICATION (app), argc, argv);
59 g_object_unref (app);
60 return stat;
61 }
62
~~~ ~~~
No signal handler is needed for GtkBulderListItemFactory. No signal handler is needed for GtkBulderListItemFactory.
@ -382,7 +364,7 @@ Instead, closure tag is appropriate in this case.
Closure tag specifies a function and the type of the return value of the function. Closure tag specifies a function and the type of the return value of the function.
~~~C ~~~C
char * const char *
get_file_name (GtkListItem *item, GFileInfo *info) { get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info)) if (! G_IS_FILE_INFO (info))
return NULL; return NULL;
@ -408,23 +390,26 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
"</interface>" "</interface>"
~~~ ~~~
- "gchararray" is the type name of strings. - The string "gchararray" is the type name of strings.
"gchar" is the same as "char" type. The type "gchar" is the same as "char".
Therefore, "gchararray" is "an array of char type", which is the same as string type. Therefore, "gchararray" is "an array of char type", which is the same as string type.
It is used to get the type of GValue object. It is used to get the type of GValue object.
GValue is a generic value and it can contain various type of values. GValue is a generic value and it can contain various type of values.
For example, the type name can be gboolean, gchar (char), gint (int), gfloat (float), gdouble (double), gchararray (char *) and so on. For example, the type name can be gboolean, gchar (char), gint (int), gfloat (float), gdouble (double), gchararray (char *) and so on.
These type names are the names of the fundamental types that are registered to the type system. These type names are the names of the fundamental types that are registered to the type system.
See [GObject tutorial](https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec5.md#gvalue). See [GObject tutorial](https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec5.md#gvalue).
- closure tag has type attribute and function attribute. - Closure tag has type attribute and function attribute.
Function attribute specifies the function name and type attribute specifies the type of the return value of the function. Function attribute specifies the function name and type attribute specifies the type of the return value of the function.
The contents of closure tag (it is between \<closure...\> and\</closure\>) is parameters of the function. The contents of closure tag (it is between \<closure...\> and\</closure\>) is parameters of the function.
`<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem. `<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
This will be the second argument of the function. This will be the second argument of the function.
The first parameter is always the GListItem instance. The first parameter is always the GListItem instance.
- `gtk_file_name` function first check the `info` parameter. - `gtk_file_name` function first checks the `info` parameter.
Because it can be NULL when GListItem `item` is unbound. Because it can be NULL when GListItem `item` is unbounded.
If its GFileInfo, then return the filename (copy of the filename). If it's GFileInfo, it returns the filename.
The filename is owned by GFileInfo object.
So, the function `get_file_name` duplicates the string to own the newly created one.
Closure tag binds the property of the outer tag (GtkLabel) to the filename.
The whole program (`list3.c`) is as follows. The whole program (`list3.c`) is as follows.
The program is located in [src/misc](../src/misc) directory. The program is located in [src/misc](../src/misc) directory.
@ -498,7 +483,6 @@ The program is located in [src/misc](../src/misc) directory.
66 g_object_unref (app); 66 g_object_unref (app);
67 return stat; 67 return stat;
68 } 68 }
69
~~~ ~~~
The ui data (xml data above) is used to build the GListItem template at runtime. The ui data (xml data above) is used to build the GListItem template at runtime.

View file

@ -7,7 +7,7 @@ It displays a GListModel as a grid, which is like a square tessellation.
![Grid](../image/list4.png) ![Grid](../image/list4.png)
This is often seen when you use a file browser like nautilus. This is often seen when you use a file browser like GNOME Files (Nautilus).
In this section, let's make a very simple file browser `list4`. In this section, let's make a very simple file browser `list4`.
It just shows the files in the current directory. It just shows the files in the current directory.
@ -32,9 +32,7 @@ GtkGridView (model property) => GtkSingleSelection (model property) => GtkDirect
![DirectoryList](../image/directorylist.png) ![DirectoryList](../image/directorylist.png)
The following is the part of the ui file `list4.ui`. The following is a part of the ui file `list4.ui`.
It defines GtkListView, GtkSingleSelection and GtkDirectoryList.
It also defines GtkGridView and GtkSingleSelection.
~~~xml ~~~xml
<object class="GtkListView" id="list"> <object class="GtkListView" id="list">
@ -59,20 +57,19 @@ It is attributes of GFileInfo such as "standard::name", "standard::icon" and "st
- standard::name is a filename. - standard::name is a filename.
- standard::icon is an icon of the file. It is a GIcon object. - standard::icon is an icon of the file. It is a GIcon object.
- standard::content-type is a content-type. - standard::content-type is a content-type.
Content-type is the same as mime type for the internet technology. Content-type is the same as mime type for the internet.
For example, "text/plain" is a text file, "text/x-csrc" is a C source code and so on. For example, "text/plain" is a text file, "text/x-csrc" is a C source code and so on.
("text/x-csrc"is not registered to IANA media types. ("text/x-csrc"is not registered to IANA media types.
Such "x-" subtype is not a standard mime type.) Such "x-" subtype is not a standard mime type.)
Content type is also used by the desktop system. Content type is also used by desktop systems.
GtkGridView has the same structure as GtkListView. GtkGridView uses the same GtkSingleSelection instance (`singleselection`).
But it is enough to specify its model property to `singleselection` which is the identification of the GtkSingleSelection. So, its model property is set with it.
Therefore the description for GtkGridView is very short.
## Ui file of the window ## Ui file of the window
Look at the screenshot of `list4` at the top of this section. The window is built with the following ui file.
The widgets are built with the following ui file. (See the screenshot at the beginning of this section).
~~~xml ~~~xml
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
@ -136,7 +133,7 @@ The widgets are built with the following ui file.
59 <property name="model"> 59 <property name="model">
60 <object class="GtkSingleSelection" id="singleselection"> 60 <object class="GtkSingleSelection" id="singleselection">
61 <property name="model"> 61 <property name="model">
62 <object class="GtkDirectoryList" id="directorylist"> 62 <object class="GtkDirectoryList" id="directory_list">
63 <property name="attributes">standard::name,standard::icon,standard::content-type</property> 63 <property name="attributes">standard::name,standard::icon,standard::content-type</property>
64 </object> 64 </object>
65 </property> 65 </property>
@ -151,25 +148,24 @@ The widgets are built with the following ui file.
~~~ ~~~
The file consists of two parts. The file consists of two parts.
The first part begins at the third line and ends at the 57th line. The first part begins at the line 3 and ends at line 57.
This part is the widgets from the top level window to the scrolled window. This part is the widgets from the top level window to the scrolled window.
It also includes two buttons. It also includes two buttons.
The second part begins at the 58th line and ends at the 71st line. The second part begins at line 58 and ends at line 71.
This is the part of GtkListView and GtkGridView. This is the part of GtkListView and GtkGridView.
They are described in the previous section.
- 13-17, 42-46: Two labels are dummy labels. - 13-17, 42-46: Two labels are dummy labels.
They just work as a space to put the two buttons at the appropriate position. They just work as a space to put the two buttons at the appropriate position.
- 19-41: GtkButton `btnlist` and `btngrid`. - 18-41: GtkButton `btnlist` and `btngrid`.
These two buttons work as selection buttons to switch from list to grid and vice versa. These two buttons work as selection buttons to switch from list to grid and vice versa.
These two buttons are connected to a stateful action `win.view`. These two buttons are connected to a stateful action `win.view`.
This action is stateful and has a parameter. This action has a parameter.
Such action consists of prefix, action name and parameter. Such action consists of prefix, action name and parameter.
The prefix of the action is `win`, which means the action belongs to the top level window. The prefix of the action is `win`, which means the action belongs to the top level window.
So, a prefix gives the scope of the action. The prefix gives the scope of the action.
The action name is `view`. The action name is `view`.
The parameters are `list` or `grid`, which show the state of the action. The parameters are `list` or `grid`, which show the state of the action.
A parameter is also called a target, because it is a target to which the buttons are clicked on to change the action state. A parameter is also called a target, because it is a target to which the action changes its state.
We often write the detailed action like "win.view::list" or "win.view::grid". We often write the detailed action like "win.view::list" or "win.view::grid".
- 21-22: The properties "action-name" and "action-target" belong to GtkActionable interface. - 21-22: The properties "action-name" and "action-target" belong to GtkActionable interface.
GtkButton implements GtkActionable. GtkButton implements GtkActionable.
@ -186,14 +182,14 @@ GtkImage has a "resource" property.
It is a GResource and GtkImage reads an image data from the resource and sets the image. It is a GResource and GtkImage reads an image data from the resource and sets the image.
This resource is built from 24x24-sized png image data, which is an original icon. This resource is built from 24x24-sized png image data, which is an original icon.
- 50-53: GtkScrolledWindow. - 50-53: GtkScrolledWindow.
Its child widget will be GtkListView or GtkGridView. Its child widget will be set with GtkListView or GtkGridView.
The action `view` is created, connected to the "activate" signal handler and inserted to the window (action map) as follows. The action `view` is created, connected to the "activate" signal handler and inserted to the window (action map) as follows.
~~~C ~~~C
act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list")); act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list"));
g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), scr); /* scr is the GtkScrolledWindow object */ g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), NULL);
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view)); g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
~~~ ~~~
The signal handler `view_activated` will be explained later. The signal handler `view_activated` will be explained later.
@ -300,10 +296,10 @@ $ cd list4; diff factory_list.ui factory_grid.ui
> <property name="xalign">0.5</property> > <property name="xalign">0.5</property>
~~~ ~~~
Each view item has two properties, "gicon" property of GtkImage and "label" property of GtkLabel. Two properties "gicon" (property of GtkImage) and "label" (property of GtkLabel) are in the ui files above.
Because GFileInfo doesn't have properties correspond to icon or filename, the factory uses closure tag to bind "gicon" and "label" properties to GFileInfo information. Because GFileInfo doesn't have properties correspond to icon or filename, the factory uses closure tag to bind "gicon" and "label" properties to GFileInfo information.
A function `get_icon` gets GIcon the GFileInfo object has. A function `get_icon` gets GIcon from the GFileInfo object.
And a function `get_file_name` gets a filename the GFileInfo object has. And a function `get_file_name` gets a filename from the GFileInfo object.
~~~C ~~~C
1 GIcon * 1 GIcon *
@ -328,11 +324,12 @@ And a function `get_file_name` gets a filename the GFileInfo object has.
20 } 20 }
~~~ ~~~
One important thing is view items own the instance or string. One important thing is the ownership of the return values.
It is achieved by `g_object_ref` to increase the reference count by one, or `strdup` to create a copy of the string. When GtkExpression (closure tag creates a GtkCClosureExpression -- a child class of GtkExpression) is evaluated,
The object or string will be automatically freed in unbinding process when the view item is recycled. the value is owned by the caller.
So, `g_obect_ref` or `g_strdup` is necessary.
## An activate signal handler of the action ## An activate signal handler of the button action
An activate signal handler `view_activate` switches the view. An activate signal handler `view_activate` switches the view.
It does two things. It does two things.
@ -342,24 +339,23 @@ It does two things.
~~~C ~~~C
1 static void 1 static void
2 view_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) { 2 view_activated(GSimpleAction *action, GVariant *parameter) {
3 GtkScrolledWindow *scr = GTK_SCROLLED_WINDOW (user_data); 3 const char *view = g_variant_get_string (parameter, NULL);
4 const char *view = g_variant_get_string (parameter, NULL); 4 const char *other;
5 const char *other; 5 char *css;
6 char *css; 6
7 7 if (strcmp (view, "list") == 0) {
8 if (strcmp (view, "list") == 0) { 8 other = "grid";
9 other = "grid"; 9 gtk_scrolled_window_set_child (scr, GTK_WIDGET (list));
10 gtk_scrolled_window_set_child (scr, list); 10 }else {
11 }else { 11 other = "list";
12 other = "list"; 12 gtk_scrolled_window_set_child (scr, GTK_WIDGET (grid));
13 gtk_scrolled_window_set_child (scr, grid); 13 }
14 } 14 css = g_strdup_printf ("button#btn%s {background: silver;} button#btn%s {background: white;}", view, other);
15 css = g_strdup_printf ("button#btn%s {background: silver;} button#btn%s {background: white;}", view, other); 15 gtk_css_provider_load_from_data (provider, css, -1);
16 gtk_css_provider_load_from_data (provider, css, -1); 16 g_free (css);
17 g_free (css); 17 g_action_change_state (G_ACTION (action), parameter);
18 g_action_change_state (G_ACTION (action), parameter); 18 }
19 }
~~~ ~~~
The second parameter of this handler is the target of the clicked button. The second parameter of this handler is the target of the clicked button.
@ -368,17 +364,17 @@ Its type is GVariant.
- If `btnlist` has been clicked, then `parameter` is a GVariant of the string "list". - If `btnlist` has been clicked, then `parameter` is a GVariant of the string "list".
- If `btngrid` has been clicked, then `parameter` is a GVariant of the string "grid". - If `btngrid` has been clicked, then `parameter` is a GVariant of the string "grid".
The third parameter `user_data` points GtkScrolledWindow, which is set in the `g_signal_connect` function. The third parameter `user_data` points NULL and it is ignored here.
- 4: `g_variant_get_string` gets the string from the GVariant variable. - 3: `g_variant_get_string` gets the string from the GVariant variable.
- 8-14: Sets the child of `scr`. - 7-13: Sets the child of `scr`.
The function `gtk_scrolled_window_set_child` decreases the reference count of the old child by one. The function `gtk_scrolled_window_set_child` decreases the reference count of the old child by one.
And it increases the reference count of the new child by one. And it increases the reference count of the new child by one.
- 15-17: Sets the CSS of the buttons. - 14-16: Sets the CSS for the buttons.
The background of the clicked button will be silver color and the other button will be white. The background of the clicked button will be silver color and the other button will be white.
- 18: Changes the state of the action. - 17: Changes the state of the action.
## Activate signal of GtkListView and GtkGridView ## Activate signal on GtkListView and GtkGridView
Views (GtkListView and GtkGridView) have an "activate" signal. Views (GtkListView and GtkGridView) have an "activate" signal.
It is emitted when an item in the view is double clicked or the enter key is pressed. It is emitted when an item in the view is double clicked or the enter key is pressed.
@ -406,10 +402,10 @@ grid_activate (GtkGridView *grid, int position, gpointer user_data) {
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL); g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
~~~ ~~~
The second parameter of the handlers is the position of the item (GFileInfo) of the GListModel. The second parameter of each handler is the position of the item (GFileInfo) of the GListModel.
So you can get the item with `g_list_model_get_item` function. So you can get the item with `g_list_model_get_item` function.
## Content type and launching an application ### Content type and application launch
The function `launch_tfe_with_file` gets a file from the GFileInfo instance. The function `launch_tfe_with_file` gets a file from the GFileInfo instance.
If the file is a text file, it launches `tfe` with the file. If the file is a text file, it launches `tfe` with the file.
@ -433,52 +429,54 @@ Content type can be got with `g_file_info_get_content_type` function.
11 if (! info) 11 if (! info)
12 return; 12 return;
13 content_type = g_file_info_get_content_type (info); 13 content_type = g_file_info_get_content_type (info);
14 g_print ("%s\n", content_type); /* This line can be commented out if unnecessary */ 14 #ifdef debug
15 if (! content_type) 15 g_print ("%s\n", content_type);
16 return; 16 #endif
17 for (i=0;i<5;++i) { 17 if (! content_type)
18 if (content_type[i] != text_type[i]) 18 return;
19 return; 19 for (i=0;i<5;++i) { /* compare the first 5 characters */
20 } 20 if (content_type[i] != text_type[i])
21 appinfo = g_app_info_create_from_commandline ("tfe", "tfe", G_APP_INFO_CREATE_NONE, &err); 21 return;
22 if (err) { 22 }
23 g_printerr ("%s\n", err->message); 23 appinfo = g_app_info_create_from_commandline ("tfe", "tfe", G_APP_INFO_CREATE_NONE, &err);
24 g_error_free (err); 24 if (err) {
25 return; 25 g_printerr ("%s\n", err->message);
26 } 26 g_error_free (err);
27 err = NULL; 27 return;
28 file = g_file_new_for_path (g_file_info_get_name (info)); 28 }
29 files = g_list_append (files, file); 29 err = NULL;
30 if (! (g_app_info_launch (appinfo, files, NULL, &err))) { 30 file = g_file_new_for_path (g_file_info_get_name (info));
31 g_printerr ("%s\n", err->message); 31 files = g_list_append (files, file);
32 g_error_free (err); 32 if (! (g_app_info_launch (appinfo, files, NULL, &err))) {
33 } 33 g_printerr ("%s\n", err->message);
34 g_list_free_full (files, g_object_unref); 34 g_error_free (err);
35 g_object_unref (appinfo); 35 }
36 } 36 g_list_free_full (files, g_object_unref);
37 g_object_unref (appinfo);
38 }
~~~ ~~~
- 13: Gets the content type of the file from GFileInfo. - 13: Gets the content type of the file from GFileInfo.
- 14: Prints the content type. - 14-16: Prints the content type if "debug" is defined.
This is only useful to know a content type of a file. This is only useful to know a content type of a file.
You can delete it if unnecessary. If you don't want this, delete or uncomment the definition `#define debug 1` iat line 6 in the source file.
- 17-20: If the content type doesn't begin with "text/", then it returns. - 17-22: If no content type or the content type doesn't begin with "text/",the function returns.
- 21: Creates GAppInfo object of `tfe` application. - 23: Creates GAppInfo object of `tfe` application.
GAppInfo is an interface and the variable `appinfo` points a GDesktopAppInfo instance. GAppInfo is an interface and the variable `appinfo` points a GDesktopAppInfo instance.
GAppInfo is a collection of information of an application. GAppInfo is a collection of information of applications.
- 30: Launches the application (`tfe`) with an argument `file`. - 32: Launches the application (`tfe`) with an argument `file`.
`g_app_info_launch` has four parameters. `g_app_info_launch` has four parameters.
The first parameter is GAppInfo object. The first parameter is GAppInfo object.
The second parameter is a list of GFile objects. The second parameter is a list of GFile objects.
In this function, only one GFile instance is given to `tfe`, but you can give more arguments. In this function, only one GFile instance is given to `tfe`, but you can give more arguments.
The third parameter is GAppLaunchContext, but this program gives NULL instead. The third parameter is GAppLaunchContext, but this program gives NULL instead.
The last parameter is the pointer to the pointer to a GError. The last parameter is the pointer to the pointer to a GError.
- 34: `g_list_free_full` frees the memories used by the list and items. - 36: `g_list_free_full` frees the memories used by the list and items.
If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient. If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient.
The function automatically determines the default application from the file and launches it. The function automatically determines the default application from the file and launches it.
For example, if the file is text, then it launches gedit with the file. For example, if the file is text, then it launches gedit with the file.
Such functionality comes from desktop. Such feature comes from desktop.
## Compilation and execution ## Compilation and execution
@ -511,7 +509,7 @@ The following shows a part of the new ui file (`list5.ui`).
<property name="model"> <property name="model">
<object class="GtkSingleSelection" id="singleselection"> <object class="GtkSingleSelection" id="singleselection">
<property name="model"> <property name="model">
<object class="GtkDirectoryList" id="directorylist"> <object class="GtkDirectoryList" id="directory_list">
<property name="attributes">standard::name,standard::icon,standard::content-type</property> <property name="attributes">standard::name,standard::icon,standard::content-type</property>
</object> </object>
</property> </property>

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
Up: [Readme.md](../Readme.md), Prev: [Section 28](sec28.md) Up: [README.md](../README.md), Prev: [Section 28](sec28.md)
# GtkColumnView # GtkColumnView
@ -13,11 +13,11 @@ Each column is GtkColumnViewColumn.
The property points a GtkSelectionModel object. The property points a GtkSelectionModel object.
- Each GtkColumnViewColumn has "factory" property. - Each GtkColumnViewColumn has "factory" property.
The property points a GtkListItemFactory (GtkSignalListItemFactory or GtkBuilderListItemFactory). The property points a GtkListItemFactory (GtkSignalListItemFactory or GtkBuilderListItemFactory).
- The factory connects GtkListItem, which belongs to GtkColumnViewColumn, and items of GtkSelectionModel. - The factory connects GtkListItem and items of GtkSelectionModel.
And the factory builds the descendants widgets of GtkColumnView to display the item on the display. And the factory builds the descendant widgets of GtkColumnView to display the item on the display.
This process is the same as the one in GtkListView. This process is the same as the one in GtkListView.
The following diagram shows the image how it works. The following diagram shows how it works.
![ColumnView](../image/column.png) ![ColumnView](../image/column.png)
@ -29,7 +29,7 @@ In addition, the example uses GtkSortListModel and GtkSorter to sort the informa
## column.ui ## column.ui
Ui file specifies whole widgets and their structure. Ui file specifies widgets and list item templates.
~~~xml ~~~xml
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
@ -39,15 +39,15 @@ Ui file specifies whole widgets and their structure.
5 <property name="default-width">800</property> 5 <property name="default-width">800</property>
6 <property name="default-height">600</property> 6 <property name="default-height">600</property>
7 <child> 7 <child>
8 <object class="GtkScrolledWindow" id="scr"> 8 <object class="GtkScrolledWindow">
9 <property name="hexpand">TRUE</property> 9 <property name="hexpand">TRUE</property>
10 <property name="vexpand">TRUE</property> 10 <property name="vexpand">TRUE</property>
11 <child> 11 <child>
12 <object class="GtkColumnView" id="columnview"> 12 <object class="GtkColumnView" id="columnview">
13 <property name="model"> 13 <property name="model">
14 <object class="GtkSingleSelection" id="singleselection"> 14 <object class="GtkNoSelection">
15 <property name="model"> 15 <property name="model">
16 <object class="GtkSortListModel" id="sortlist"> 16 <object class="GtkSortListModel">
17 <property name="model"> 17 <property name="model">
18 <object class="GtkDirectoryList" id="directorylist"> 18 <object class="GtkDirectoryList" id="directorylist">
19 <property name="attributes">standard::name,standard::icon,standard::size,time::modified</property> 19 <property name="attributes">standard::name,standard::icon,standard::size,time::modified</property>
@ -61,7 +61,7 @@ Ui file specifies whole widgets and their structure.
27 </object> 27 </object>
28 </property> 28 </property>
29 <child> 29 <child>
30 <object class="GtkColumnViewColumn" id="column1"> 30 <object class="GtkColumnViewColumn">
31 <property name="title">Name</property> 31 <property name="title">Name</property>
32 <property name="expand">TRUE</property> 32 <property name="expand">TRUE</property>
33 <property name="factory"> 33 <property name="factory">
@ -102,7 +102,7 @@ Ui file specifies whole widgets and their structure.
68 </object> 68 </object>
69 </property> 69 </property>
70 <property name="sorter"> 70 <property name="sorter">
71 <object class="GtkStringSorter" id="sorter_name"> 71 <object class="GtkStringSorter">
72 <property name="expression"> 72 <property name="expression">
73 <closure type="gchararray" function="get_file_name"> 73 <closure type="gchararray" function="get_file_name">
74 </closure> 74 </closure>
@ -112,7 +112,7 @@ Ui file specifies whole widgets and their structure.
78 </object> 78 </object>
79 </child> 79 </child>
80 <child> 80 <child>
81 <object class="GtkColumnViewColumn" id="column2"> 81 <object class="GtkColumnViewColumn">
82 <property name="title">Size</property> 82 <property name="title">Size</property>
83 <property name="factory"> 83 <property name="factory">
84 <object class="GtkBuilderListItemFactory"> 84 <object class="GtkBuilderListItemFactory">
@ -125,7 +125,7 @@ Ui file specifies whole widgets and their structure.
91 <property name="hexpand">TRUE</property> 91 <property name="hexpand">TRUE</property>
92 <property name="xalign">0</property> 92 <property name="xalign">0</property>
93 <binding name="label"> 93 <binding name="label">
94 <closure type="gchararray" function="get_file_size_factory"> 94 <closure type="gint64" function="get_file_size_factory">
95 <lookup name="item">GtkListItem</lookup> 95 <lookup name="item">GtkListItem</lookup>
96 </closure> 96 </closure>
97 </binding> 97 </binding>
@ -137,7 +137,7 @@ Ui file specifies whole widgets and their structure.
103 </object> 103 </object>
104 </property> 104 </property>
105 <property name="sorter"> 105 <property name="sorter">
106 <object class="GtkNumericSorter" id="sorter_size"> 106 <object class="GtkNumericSorter">
107 <property name="expression"> 107 <property name="expression">
108 <closure type="gint64" function="get_file_size"> 108 <closure type="gint64" function="get_file_size">
109 </closure> 109 </closure>
@ -148,7 +148,7 @@ Ui file specifies whole widgets and their structure.
114 </object> 114 </object>
115 </child> 115 </child>
116 <child> 116 <child>
117 <object class="GtkColumnViewColumn" id="column3"> 117 <object class="GtkColumnViewColumn">
118 <property name="title">Date modified</property> 118 <property name="title">Date modified</property>
119 <property name="factory"> 119 <property name="factory">
120 <object class="GtkBuilderListItemFactory"> 120 <object class="GtkBuilderListItemFactory">
@ -173,7 +173,7 @@ Ui file specifies whole widgets and their structure.
139 </object> 139 </object>
140 </property> 140 </property>
141 <property name="sorter"> 141 <property name="sorter">
142 <object class="GtkNumericSorter" id="sorter_datetime_modified"> 142 <object class="GtkNumericSorter">
143 <property name="expression"> 143 <property name="expression">
144 <closure type="gint64" function="get_file_unixtime_modified"> 144 <closure type="gint64" function="get_file_unixtime_modified">
145 </closure> 145 </closure>
@ -191,18 +191,18 @@ Ui file specifies whole widgets and their structure.
157 </interface> 157 </interface>
~~~ ~~~
- 3-12: Widget parent-child relationship is GtkApplicationWindow => GtkScrolledWindow => GtkColumnView. - 3-12: GtkApplicationWindow has a child widget GtkScrolledWindow.
GtkScrolledWindoww has a child widget GtkColumnView.
- 12-18: GtkColumnView has "model" property. - 12-18: GtkColumnView has "model" property.
It points GtkSelectionModel interface. It points GtkSelectionModel interface.
In this ui file, GtkSingleSelection is used as GtkSelectionModel. GtkNoSelection class is used as GtkSelectionModel.
GtkSingleSelection is an object that implements GtkSelectionModel.
And again, it has "model" property. And again, it has "model" property.
It points GtkSortListModel. It points GtkSortListModel.
This list model supports sorting the list. This list model supports sorting the list.
It will be explained in the later subsection. It will be explained in the later subsection.
And it also has "model" property. And it also has "model" property.
It points GtkDirectoryList. It points GtkDirectoryList.
Therefore, the chain is: GtkColumnView => GtkSingleSelection => GtkSortListModel => GtkDirectoryList. Therefore, the chain is: GtkColumnView => GtkNoSelection => GtkSortListModel => GtkDirectoryList.
- 18-20: GtkDirectoryList. - 18-20: GtkDirectoryList.
It is a list of GFileInfo, which holds information of files under a directory. It is a list of GFileInfo, which holds information of files under a directory.
It has "attributes" property. It has "attributes" property.
@ -213,30 +213,27 @@ It specifies what attributes is kept in each GFileInfo.
- "time::modified" is the date and time the file was last modified. - "time::modified" is the date and time the file was last modified.
- 29-79: The first GtkColumnViewColumn object. - 29-79: The first GtkColumnViewColumn object.
There are four properties, "title", "expand", factory" and "sorter". There are four properties, "title", "expand", factory" and "sorter".
- 31: Sets the "title" property with "Name". - 31: Sets the "title" property to "Name".
This is the title on the header of the column. This is the title on the header of the column.
- 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible. - 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible.
(See the image above). (See the image above).
- 33- 69: Sets the "factory" property with GtkBuilderListItemFactory. - 33- 69: Sets the "factory" property to GtkBuilderListItemFactory.
The factory has "bytes" property which holds a ui string to define a template to build GtkListItem composite widget. The factory has "bytes" property which holds a ui string to define a template to build GtkListItem composite widget.
The CDATA section (line 36-66) is the ui string to put into the "bytes" property. The CDATA section (line 36-66) is the ui string to put into the "bytes" property.
The contents are the same as the ui file `factory_list.ui` in the section 27. The contents are the same as the ui file `factory_list.ui` in the section 27.
- 70-77: Sets the "sorter" property with GtkStringSorter object. - 70-77: Sets the "sorter" property to GtkStringSorter object.
This object provides a sorter that compares strings. This object provides a sorter that compares strings.
It has "expression" property which is set with GtkExpression. It has "expression" property.
A closure tag with a string type function `get_file_name` is used here. A closure tag with a string type function `get_file_name` is used here.
The function will be explained later. The function will be explained later.
- 80-115: The second GtkColumnViewColumn object. - 80-115: The second GtkColumnViewColumn object.
Its "title", "factory" and "sorter" properties are set. Its sorter property is set to GtkNumericSorter.
GtkNumericSorter is used.
- 116-151: The third GtkColumnViewColumn object. - 116-151: The third GtkColumnViewColumn object.
Its "title", "factory" and "sorter" properties are set. Its sorter property is set to GtkNumericSorter.
GtkNumericSorter is used.
## GtkSortListModel and GtkSorter ## GtkSortListModel and GtkSorter
GtkSortListModel is a list model that sorts its elements according to a GtkSorter. GtkSortListModel is a list model that sorts its elements according to a GtkSorter instance assigned to the "sorter" property.
It has "sorter" property that is set with GtkSorter.
The property is bound to "sorter" property of GtkColumnView in line 22 to 24. The property is bound to "sorter" property of GtkColumnView in line 22 to 24.
~~~xml ~~~xml
@ -255,21 +252,25 @@ If the user clicks the header of another column, then the "sorter" property of t
The binding above makes a indirect connection between the "sorter" property of GtkSortListModel and the "sorter" property of each column. The binding above makes a indirect connection between the "sorter" property of GtkSortListModel and the "sorter" property of each column.
GtkSorter compares two items (GObject or its descendant).
GtkSorter has several child objects. GtkSorter has several child objects.
- GtkStringSorter compares strings. - GtkStringSorter compares strings taken from the items.
- GtkNumericSorter compares numbers. - GtkNumericSorter compares numbers taken from the items.
- GtkCustomSorter uses a callback to compare. - GtkCustomSorter uses a callback to compare.
- GtkMultiSorter combines multiple sorters. - GtkMultiSorter combines multiple sorters.
The example uses GtkStringSorter and GtkNumericSorter. The example uses GtkStringSorter and GtkNumericSorter.
GtkStringSorter uses GtkExpression to get the strings from the objects. GtkStringSorter uses GtkExpression to get the strings from the items (objects).
The GtkExpression is stored in the "expression" property of GtkStringSorter. The GtkExpression is stored in the "expression" property of the GtkStringSorter.
For example, in the ui file above, the GtkExpression is in the line 71 to 76. When GtkStringSorter compares two items, it evaluates the expression by calling `gtk_expression_evaluate` function.
It assigns each item to the second argument ('this' object) of the function.
In the ui file above, the GtkExpression is in the line 71 to 76.
~~~xml ~~~xml
<object class="GtkStringSorter" id="sorter_name"> <object class="GtkStringSorter">
<property name="expression"> <property name="expression">
<closure type="gchararray" function="get_file_name"> <closure type="gchararray" function="get_file_name">
</closure> </closure>
@ -282,24 +283,23 @@ The GtkExpression calls `get_file_name` function when it is evaluated.
~~~C ~~~C
1 char * 1 char *
2 get_file_name (GFileInfo *info) { 2 get_file_name (GFileInfo *info) {
3 g_return_val_if_fail (G_IS_FILE_INFO (info), NULL); 3 return G_IS_FILE_INFO (info) ? g_strdup(g_file_info_get_name (info)) : NULL;
4 4 }
5 return g_strdup(g_file_info_get_name (info));
6 }
~~~ ~~~
The function is given the item (GFileInfo) of the GtkSortListModel as an argument (`this` object). The function is given the item (GFileInfo) of the GtkSortListModel as an argument (`this` object).
But you need to be careful that it can be NULL while the list item is being recycled.
So, `G_IS_FILE_INFO (info)` is always necessary in callback functions.
The function retrieves a filename from `info`. The function retrieves a filename from `info`.
The string is owned by `info` so it is necessary to duplicate it. The string is owned by `info` so it is necessary to duplicate it.
And it returns the copied string. And it returns the copied string.
The string will be owned by the expression.
GtkNumericSorter compares numbers. GtkNumericSorter compares numbers.
It is used in the line 106 to 112 and line 142 to 148. It is used in the line 106 to 112 and line 142 to 148.
The lines from 106 to 112 is: The lines from 106 to 112 is:
~~~xml ~~~xml
<object class="GtkNumericSorter" id="sorter_size"> <object class="GtkNumericSorter">
<property name="expression"> <property name="expression">
<closure type="gint64" function="get_file_size"> <closure type="gint64" function="get_file_size">
</closure> </closure>
@ -313,10 +313,8 @@ The closure tag specifies a callback function `get_file_size`.
~~~C ~~~C
1 goffset 1 goffset
2 get_file_size (GFileInfo *info) { 2 get_file_size (GFileInfo *info) {
3 g_return_val_if_fail (G_IS_FILE_INFO (info), -1); 3 return G_IS_FILE_INFO (info) ? g_file_info_get_size (info): -1;
4 4 }
5 return g_file_info_get_size (info);
6 }
~~~ ~~~
It just returns the size of `info`. It just returns the size of `info`.
@ -340,13 +338,11 @@ The closure tag specifies a callback function `get_file_unixtime_modified`.
~~~C ~~~C
1 gint64 1 gint64
2 get_file_unixtime_modified (GFileInfo *info) { 2 get_file_unixtime_modified (GFileInfo *info) {
3 g_return_val_if_fail (G_IS_FILE_INFO (info), -1); 3 GDateTime *dt;
4 4
5 GDateTime *dt; 5 dt = G_IS_FILE_INFO (info) ? g_file_info_get_modification_date_time (info) : NULL;
6 6 return dt ? g_date_time_to_unix (dt) : -1;
7 dt = g_file_info_get_modification_date_time (info); 7 }
8 return g_date_time_to_unix (dt);
9 }
~~~ ~~~
It gets the modification date and time (GDateTime type) of `info`. It gets the modification date and time (GDateTime type) of `info`.
@ -357,6 +353,7 @@ It returns the unix time (gint64 type).
## column.c ## column.c
`column.c` is as follows. `column.c` is as follows.
It is simple and short thanks to `column.ui`.
~~~C ~~~C
1 #include <gtk/gtk.h> 1 #include <gtk/gtk.h>
@ -365,132 +362,97 @@ It returns the unix time (gint64 type).
4 GIcon * 4 GIcon *
5 get_icon_factory (GtkListItem *item, GFileInfo *info) { 5 get_icon_factory (GtkListItem *item, GFileInfo *info) {
6 GIcon *icon; 6 GIcon *icon;
7 if (! G_IS_FILE_INFO (info)) 7
8 return NULL; 8 /* g_file_info_get_icon can return NULL */
9 else { 9 icon = G_IS_FILE_INFO (info) ? g_file_info_get_icon (info) : NULL;
10 icon = g_file_info_get_icon (info); 10 return icon ? g_object_ref (icon) : NULL;
11 g_object_ref (icon); 11 }
12 return icon; 12
13 } 13 char *
14 } 14 get_file_name_factory (GtkListItem *item, GFileInfo *info) {
15 15 return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
16 char * 16 }
17 get_file_name_factory (GtkListItem *item, GFileInfo *info) { 17
18 if (! G_IS_FILE_INFO (info)) 18 /* goffset is defined as gint64 */
19 return NULL; 19 /* It is used for file offsets. */
20 else 20 goffset
21 return g_strdup (g_file_info_get_name (info)); 21 get_file_size_factory (GtkListItem *item, GFileInfo *info) {
22 } 22 return G_IS_FILE_INFO (info) ? g_file_info_get_size (info) : -1;
23 23 }
24 char * 24
25 get_file_size_factory (GtkListItem *item, GFileInfo *info) { 25 char *
26 /* goffset is gint64 */ 26 get_file_time_modified_factory (GtkListItem *item, GFileInfo *info) {
27 goffset size; 27 GDateTime *dt;
28 28
29 if (! G_IS_FILE_INFO (info)) 29 /* g_file_info_get_modification_date_time can return NULL */
30 return NULL; 30 dt = G_IS_FILE_INFO (info) ? g_file_info_get_modification_date_time (info) : NULL;
31 else { 31 return dt ? g_date_time_format (dt, "%F") : NULL;
32 size = g_file_info_get_size (info); 32 }
33 return g_strdup_printf ("%ld", (long int) size); 33
34 } 34 /* Functions (closures) for GtkSorter */
35 } 35 char *
36 36 get_file_name (GFileInfo *info) {
37 char * 37 return G_IS_FILE_INFO (info) ? g_strdup(g_file_info_get_name (info)) : NULL;
38 get_file_time_modified_factory (GtkListItem *item, GFileInfo *info) { 38 }
39 GDateTime *dt; 39
40 40 goffset
41 if (! G_IS_FILE_INFO (info)) 41 get_file_size (GFileInfo *info) {
42 return NULL; 42 return G_IS_FILE_INFO (info) ? g_file_info_get_size (info): -1;
43 else { 43 }
44 dt = g_file_info_get_modification_date_time (info); 44
45 return g_date_time_format (dt, "%F"); 45 gint64
46 } 46 get_file_unixtime_modified (GFileInfo *info) {
47 } 47 GDateTime *dt;
48 48
49 /* Functions (closures) for GtkSorter */ 49 dt = G_IS_FILE_INFO (info) ? g_file_info_get_modification_date_time (info) : NULL;
50 char * 50 return dt ? g_date_time_to_unix (dt) : -1;
51 get_file_name (GFileInfo *info) { 51 }
52 g_return_val_if_fail (G_IS_FILE_INFO (info), NULL); 52
53 53 static void
54 return g_strdup(g_file_info_get_name (info)); 54 app_activate (GApplication *application) {
55 } 55 GtkApplication *app = GTK_APPLICATION (application);
56 56 gtk_window_present (gtk_application_get_active_window(app));
57 goffset 57 }
58 get_file_size (GFileInfo *info) { 58
59 g_return_val_if_fail (G_IS_FILE_INFO (info), -1); 59 static void
60 60 app_startup (GApplication *application) {
61 return g_file_info_get_size (info); 61 GtkApplication *app = GTK_APPLICATION (application);
62 } 62 GFile *file;
63 63 GtkBuilder *build = gtk_builder_new_from_resource ("/com/github/ToshioCP/column/column.ui");
64 gint64 64 GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
65 get_file_unixtime_modified (GFileInfo *info) { 65 GtkDirectoryList *directorylist = GTK_DIRECTORY_LIST (gtk_builder_get_object (build, "directorylist"));
66 g_return_val_if_fail (G_IS_FILE_INFO (info), -1); 66 g_object_unref (build);
67 67
68 GDateTime *dt; 68 gtk_window_set_application (GTK_WINDOW (win), app);
69 69
70 dt = g_file_info_get_modification_date_time (info); 70 file = g_file_new_for_path (".");
71 return g_date_time_to_unix (dt); 71 gtk_directory_list_set_file (directorylist, file);
72 } 72 g_object_unref (file);
73 73 }
74 /* ----- activate, open, startup handlers ----- */ 74
75 static void 75 #define APPLICATION_ID "com.github.ToshioCP.columnview"
76 app_activate (GApplication *application) { 76
77 GtkApplication *app = GTK_APPLICATION (application); 77 int
78 GFile *file; 78 main (int argc, char **argv) {
79 79 GtkApplication *app;
80 GtkBuilder *build = gtk_builder_new_from_resource ("/com/github/ToshioCP/column/column.ui"); 80 int stat;
81 GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (build, "win")); 81
82 GtkDirectoryList *directorylist = GTK_DIRECTORY_LIST (gtk_builder_get_object (build, "directorylist")); 82 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
83 g_object_unref (build); 83
84 84 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
85 gtk_window_set_application (GTK_WINDOW (win), app); 85 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
86 86
87 file = g_file_new_for_path ("."); 87 stat =g_application_run (G_APPLICATION (app), argc, argv);
88 gtk_directory_list_set_file (directorylist, file); 88 g_object_unref (app);
89 g_object_unref (file); 89 return stat;
90 90 }
91 gtk_widget_show (win); 91
92 }
93
94 static void
95 app_startup (GApplication *application) {
96 }
97
98 #define APPLICATION_ID "com.github.ToshioCP.columnview"
99
100 int
101 main (int argc, char **argv) {
102 GtkApplication *app;
103 int stat;
104
105 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
106
107 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
108 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
109 /* g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);*/
110
111 stat =g_application_run (G_APPLICATION (app), argc, argv);
112 g_object_unref (app);
113 return stat;
114 }
115
~~~ ~~~
- 4-47: Functions for the closure tag in the "bytes" property of GtkBuilderListItemFactory.
These are almost same as the functions in section 26 and 26.
- 50-72: Functions for the closure in the expression property of GtkStringSorter or GtkNumericSorter.
- 75-92: `app_activate` is an "activate" handler of GApplication.
- 80-83: Builds objects with ui resource and gets `win` and `directorylist`.
- 85: Sets the application of the top level window with `app`.
- 87-89: Sets the file of `directorylist` with "." (current directory).
- 94-96: Startup handler.
- 98-114: `main` function.
`exp.c` is simple and short thanks to `exp.ui`.
## Compilation and execution. ## Compilation and execution.
All the source files are in [src/column](../src/column) directory. All the source files are in [`src/column`](../src/column) directory.
Change your current directory to the directory and type the following. Change your current directory to the directory and type the following.
~~~ ~~~
@ -509,5 +471,4 @@ If you click the header of another column, then the whole lists are sorted by th
GtkColumnView is very useful and it can manage very big GListModel. GtkColumnView is very useful and it can manage very big GListModel.
It is possible to use it for file list, application list, database frontend and so on. It is possible to use it for file list, application list, database frontend and so on.
Up: [README.md](../README.md), Prev: [Section 28](sec28.md)
Up: [Readme.md](../Readme.md), Prev: [Section 28](sec28.md)

View file

@ -59,9 +59,27 @@ In a broad sense, object has wider meaning than instance.
So, readers should be careful of the contexts to find the meaning of "object". So, readers should be careful of the contexts to find the meaning of "object".
In many cases, object and instance are the same. In many cases, object and instance are the same.
The function `gtk_application_new` has two parameters.
- Application ID (com.github.ToshioCP.pr1).
It is used to distinguish applications by the system.
The format is reverse-DNS.
See [GNOME Developer Documentation -- Application ID](https://developer.gnome.org/documentation/tutorials/application-id.html) for further information.
- Application flag (G\_APPLICATION\_DEFAULT\_FLAGS).
If the application runs without any arguments, the flag is G\_APPLICATION\_DEFAULT\_FLAGS.
Otherwise, you need other flags.
See [GIO API reference](https://docs.gtk.org/gio/flags.ApplicationFlags.html) for further information.
To compile this, the following command needs to be run. To compile this, the following command needs to be run.
The string `pr1.c` is the filename of the C source code above. The string `pr1.c` is the filename of the C source code above.
Notice: If your GLib-2.0 version is older than 2.74, use `G_APPLICATION_FLAGS_NONE` instead of `G_APPLICATION_DEFAULT_FLAGS`.
It is an old flag replaced by `G_APPLICATION_DEFAULT_FLAGS` and deprecated since version 2.74.
However, many distributions use GLib-2.0 version 2.72 or older, for example, Ubuntu 22.04 LTS.
~~~ ~~~
$ gcc `pkg-config --cflags gtk4` pr1.c `pkg-config --libs gtk4` $ gcc `pkg-config --cflags gtk4` pr1.c `pkg-config --libs gtk4`
~~~ ~~~