mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-11 20:03:35 +01:00
Update gfm files of the section 16-30.
This commit is contained in:
parent
e0897922ce
commit
c84cffd8ef
5 changed files with 961 additions and 875 deletions
198
gfm/sec26.md
198
gfm/sec26.md
|
@ -3,29 +3,29 @@ Up: [README.md](../README.md), Prev: [Section 25](sec25.md), Next: [Section 27]
|
|||
# GtkListView
|
||||
|
||||
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.
|
||||
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.
|
||||
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
|
||||
|
||||
A list is a sequential data structure.
|
||||
For example, an ordered string sequence "one", "two", "three", "four" is a list.
|
||||
Each element of the list 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.
|
||||
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 items of the list.
|
||||
And it has a start point.
|
||||
So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...).
|
||||
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.
|
||||
It is a zero-based list of the same type of GObject objects, or objects that implement the same interface.
|
||||
An object implements GListModel is usually not a widget.
|
||||
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 not a widget.
|
||||
So, the list is not displayed on the screen directly.
|
||||
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.
|
||||
|
@ -33,16 +33,11 @@ GtkListItemFactory object maps items in the list to GListView.
|
|||
|
||||
![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
|
||||
|
||||
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.
|
||||
The word "GObject" here means "GObject class or its descendant class".
|
||||
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.
|
||||
|
||||
|
@ -51,7 +46,7 @@ char *array[] = {"one", "two", "three", "four", NULL};
|
|||
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".
|
||||
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_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
|
||||
|
||||
|
@ -101,7 +96,7 @@ There are four signals.
|
|||
|
||||
1. "setup" is emitted to set up GtkListItem object.
|
||||
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).
|
||||
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.
|
||||
|
@ -121,7 +116,7 @@ GtkNoSelection is used, so user can't select any item.
|
|||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
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);
|
||||
6 gtk_list_item_set_child (listitem, lb);
|
||||
7 }
|
||||
|
@ -129,40 +124,40 @@ GtkNoSelection is used, so user can't select any item.
|
|||
9 static void
|
||||
10 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
|
||||
11 GtkWidget *lb = gtk_list_item_get_child (listitem);
|
||||
12 GtkStringObject *strobj = gtk_list_item_get_item (listitem);
|
||||
13 const char *text = gtk_string_object_get_string (strobj);
|
||||
14
|
||||
15 gtk_label_set_text (GTK_LABEL (lb), text);
|
||||
16 }
|
||||
17
|
||||
18 static void
|
||||
19 unbind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
|
||||
20 /* There's nothing to do here. */
|
||||
21 /* If you does something like setting a signal in bind_cb, */
|
||||
22 /* then disconnecting the signal is necessary in unbind_cb. */
|
||||
23 }
|
||||
24
|
||||
25 static void
|
||||
26 teardown_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
|
||||
27 gtk_list_item_set_child (listitem, NULL);
|
||||
28 /* When the child of listitem is set to NULL, the reference to GtkLabel will be released and lb will be destroyed. */
|
||||
29 /* Therefore, g_object_unref () for the GtkLabel object doesn't need in the user code. */
|
||||
30 }
|
||||
31
|
||||
32 /* ----- activate, open, startup handlers ----- */
|
||||
33 static void
|
||||
34 app_activate (GApplication *application) {
|
||||
35 GtkApplication *app = GTK_APPLICATION (application);
|
||||
36 GtkWidget *win = gtk_application_window_new (app);
|
||||
37 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||
38 GtkWidget *scr = gtk_scrolled_window_new ();
|
||||
39 gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
40
|
||||
41 char *array[] = {
|
||||
42 "one", "two", "three", "four", NULL
|
||||
43 };
|
||||
44 GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
|
||||
45 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (sl));
|
||||
12 /* Strobj is owned by the instance. Caller mustn't change or destroy it. */
|
||||
13 GtkStringObject *strobj = gtk_list_item_get_item (listitem);
|
||||
14 const char *text = gtk_string_object_get_string (strobj);
|
||||
15
|
||||
16 gtk_label_set_text (GTK_LABEL (lb), text);
|
||||
17 }
|
||||
18
|
||||
19 static void
|
||||
20 unbind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
|
||||
21 /* There's nothing to do here. */
|
||||
22 }
|
||||
23
|
||||
24 static void
|
||||
25 teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
|
||||
26 gtk_list_item_set_child (listitem, NULL);
|
||||
27 /* The previous child is destroyed automatically. */
|
||||
28 }
|
||||
29
|
||||
30 static void
|
||||
31 app_activate (GApplication *application) {
|
||||
32 GtkApplication *app = GTK_APPLICATION (application);
|
||||
33 GtkWidget *win = gtk_application_window_new (app);
|
||||
34 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||
35 GtkWidget *scr = gtk_scrolled_window_new ();
|
||||
36 gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
37
|
||||
38 char *array[] = {
|
||||
39 "one", "two", "three", "four", NULL
|
||||
40 };
|
||||
41 /* sl is owned by ns */
|
||||
42 /* ns and factory are owned by lv. */
|
||||
43 /* Therefore, you don't need to care about their destruction. */
|
||||
44 GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
|
||||
45 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (sl));
|
||||
46
|
||||
47 GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
|
||||
48 g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL);
|
||||
|
@ -175,34 +170,26 @@ GtkNoSelection is used, so user can't select any item.
|
|||
55 gtk_window_present (GTK_WINDOW (win));
|
||||
56 }
|
||||
57
|
||||
58 static void
|
||||
59 app_startup (GApplication *application) {
|
||||
60 }
|
||||
61
|
||||
62 /* ----- main ----- */
|
||||
63 #define APPLICATION_ID "com.github.ToshioCP.list1"
|
||||
64
|
||||
65 int
|
||||
66 main (int argc, char **argv) {
|
||||
67 GtkApplication *app;
|
||||
68 int stat;
|
||||
58 /* ----- main ----- */
|
||||
59 #define APPLICATION_ID "com.github.ToshioCP.list1"
|
||||
60
|
||||
61 int
|
||||
62 main (int argc, char **argv) {
|
||||
63 GtkApplication *app;
|
||||
64 int stat;
|
||||
65
|
||||
66 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
67
|
||||
68 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
69
|
||||
70 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
71
|
||||
72 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
73 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
74
|
||||
75 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
76 g_object_unref (app);
|
||||
77 return stat;
|
||||
78 }
|
||||
79
|
||||
70 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
71 g_object_unref (app);
|
||||
72 return stat;
|
||||
73 }
|
||||
~~~
|
||||
|
||||
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.
|
||||
(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.)
|
||||
Make a shell script below and save it to your bin directory, for example `$HOME/bin`.
|
||||
|
||||
~~~Shell
|
||||
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.
|
||||
|
||||
~~~
|
||||
$ 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
|
||||
$ ./a.out
|
||||
~~~
|
||||
|
||||
Then, `list1.c` has been compiled and executed.
|
||||
Then, the following window appears.
|
||||
|
||||
![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.
|
||||
|
||||
### 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));
|
||||
39 }
|
||||
40
|
||||
41 static void
|
||||
42 app_startup (GApplication *application) {
|
||||
43 }
|
||||
44
|
||||
45 /* ----- main ----- */
|
||||
46 #define APPLICATION_ID "com.github.ToshioCP.list2"
|
||||
47
|
||||
48 int
|
||||
49 main (int argc, char **argv) {
|
||||
50 GtkApplication *app;
|
||||
51 int stat;
|
||||
41 /* ----- main ----- */
|
||||
42 #define APPLICATION_ID "com.github.ToshioCP.list2"
|
||||
43
|
||||
44 int
|
||||
45 main (int argc, char **argv) {
|
||||
46 GtkApplication *app;
|
||||
47 int stat;
|
||||
48
|
||||
49 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
50
|
||||
51 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
52
|
||||
53 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
54
|
||||
55 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
56 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
53 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
54 g_object_unref (app);
|
||||
55 return stat;
|
||||
56 }
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
~~~C
|
||||
char *
|
||||
const char *
|
||||
get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||
if (! G_IS_FILE_INFO (info))
|
||||
return NULL;
|
||||
|
@ -408,23 +390,26 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
|
|||
"</interface>"
|
||||
~~~
|
||||
|
||||
- "gchararray" is the type name of strings.
|
||||
"gchar" is the same as "char" type.
|
||||
- The string "gchararray" is the type name of strings.
|
||||
The type "gchar" is the same as "char".
|
||||
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.
|
||||
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.
|
||||
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).
|
||||
- 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.
|
||||
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.
|
||||
This will be the second argument of the function.
|
||||
The first parameter is always the GListItem instance.
|
||||
- `gtk_file_name` function first check the `info` parameter.
|
||||
Because it can be NULL when GListItem `item` is unbound.
|
||||
If its GFileInfo, then return the filename (copy of the filename).
|
||||
- `gtk_file_name` function first checks the `info` parameter.
|
||||
Because it can be NULL when GListItem `item` is unbounded.
|
||||
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 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);
|
||||
67 return stat;
|
||||
68 }
|
||||
69
|
||||
~~~
|
||||
|
||||
The ui data (xml data above) is used to build the GListItem template at runtime.
|
||||
|
|
174
gfm/sec27.md
174
gfm/sec27.md
|
@ -7,7 +7,7 @@ It displays a GListModel as a grid, which is like a square tessellation.
|
|||
|
||||
![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`.
|
||||
It just shows the files in the current directory.
|
||||
|
@ -32,9 +32,7 @@ GtkGridView (model property) => GtkSingleSelection (model property) => GtkDirect
|
|||
|
||||
![DirectoryList](../image/directorylist.png)
|
||||
|
||||
The following is the part of the ui file `list4.ui`.
|
||||
It defines GtkListView, GtkSingleSelection and GtkDirectoryList.
|
||||
It also defines GtkGridView and GtkSingleSelection.
|
||||
The following is a part of the ui file `list4.ui`.
|
||||
|
||||
~~~xml
|
||||
<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::icon is an icon of the file. It is a GIcon object.
|
||||
- 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.
|
||||
("text/x-csrc"is not registered to IANA media types.
|
||||
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.
|
||||
But it is enough to specify its model property to `singleselection` which is the identification of the GtkSingleSelection.
|
||||
Therefore the description for GtkGridView is very short.
|
||||
GtkGridView uses the same GtkSingleSelection instance (`singleselection`).
|
||||
So, its model property is set with it.
|
||||
|
||||
## Ui file of the window
|
||||
|
||||
Look at the screenshot of `list4` at the top of this section.
|
||||
The widgets are built with the following ui file.
|
||||
The window is built with the following ui file.
|
||||
(See the screenshot at the beginning of this section).
|
||||
|
||||
~~~xml
|
||||
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">
|
||||
60 <object class="GtkSingleSelection" id="singleselection">
|
||||
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>
|
||||
64 </object>
|
||||
65 </property>
|
||||
|
@ -151,25 +148,24 @@ The widgets are built with the following ui file.
|
|||
~~~
|
||||
|
||||
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.
|
||||
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.
|
||||
They are described in the previous section.
|
||||
|
||||
- 13-17, 42-46: Two labels are dummy labels.
|
||||
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 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.
|
||||
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 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".
|
||||
- 21-22: The properties "action-name" and "action-target" belong to GtkActionable interface.
|
||||
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.
|
||||
This resource is built from 24x24-sized png image data, which is an original icon.
|
||||
- 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.
|
||||
|
||||
~~~C
|
||||
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_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
|
||||
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), NULL);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
|
||||
~~~
|
||||
|
||||
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>
|
||||
~~~
|
||||
|
||||
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.
|
||||
A function `get_icon` gets GIcon the GFileInfo object has.
|
||||
And a function `get_file_name` gets a filename the GFileInfo object has.
|
||||
A function `get_icon` gets GIcon from the GFileInfo object.
|
||||
And a function `get_file_name` gets a filename from the GFileInfo object.
|
||||
|
||||
~~~C
|
||||
1 GIcon *
|
||||
|
@ -328,11 +324,12 @@ And a function `get_file_name` gets a filename the GFileInfo object has.
|
|||
20 }
|
||||
~~~
|
||||
|
||||
One important thing is view items own the instance or string.
|
||||
It is achieved by `g_object_ref` to increase the reference count by one, or `strdup` to create a copy of the string.
|
||||
The object or string will be automatically freed in unbinding process when the view item is recycled.
|
||||
One important thing is the ownership of the return values.
|
||||
When GtkExpression (closure tag creates a GtkCClosureExpression -- a child class of GtkExpression) is evaluated,
|
||||
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.
|
||||
It does two things.
|
||||
|
@ -342,24 +339,23 @@ It does two things.
|
|||
|
||||
~~~C
|
||||
1 static void
|
||||
2 view_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
3 GtkScrolledWindow *scr = GTK_SCROLLED_WINDOW (user_data);
|
||||
4 const char *view = g_variant_get_string (parameter, NULL);
|
||||
5 const char *other;
|
||||
6 char *css;
|
||||
7
|
||||
8 if (strcmp (view, "list") == 0) {
|
||||
9 other = "grid";
|
||||
10 gtk_scrolled_window_set_child (scr, list);
|
||||
11 }else {
|
||||
12 other = "list";
|
||||
13 gtk_scrolled_window_set_child (scr, grid);
|
||||
14 }
|
||||
15 css = g_strdup_printf ("button#btn%s {background: silver;} button#btn%s {background: white;}", view, other);
|
||||
16 gtk_css_provider_load_from_data (provider, css, -1);
|
||||
17 g_free (css);
|
||||
18 g_action_change_state (G_ACTION (action), parameter);
|
||||
19 }
|
||||
2 view_activated(GSimpleAction *action, GVariant *parameter) {
|
||||
3 const char *view = g_variant_get_string (parameter, NULL);
|
||||
4 const char *other;
|
||||
5 char *css;
|
||||
6
|
||||
7 if (strcmp (view, "list") == 0) {
|
||||
8 other = "grid";
|
||||
9 gtk_scrolled_window_set_child (scr, GTK_WIDGET (list));
|
||||
10 }else {
|
||||
11 other = "list";
|
||||
12 gtk_scrolled_window_set_child (scr, GTK_WIDGET (grid));
|
||||
13 }
|
||||
14 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 g_free (css);
|
||||
17 g_action_change_state (G_ACTION (action), parameter);
|
||||
18 }
|
||||
~~~
|
||||
|
||||
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 `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.
|
||||
- 8-14: Sets the child of `scr`.
|
||||
- 3: `g_variant_get_string` gets the string from the GVariant variable.
|
||||
- 7-13: Sets the child of `scr`.
|
||||
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.
|
||||
- 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.
|
||||
- 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.
|
||||
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);
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
||||
## Content type and launching an application
|
||||
### Content type and application launch
|
||||
|
||||
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.
|
||||
|
@ -433,52 +429,54 @@ Content type can be got with `g_file_info_get_content_type` function.
|
|||
11 if (! info)
|
||||
12 return;
|
||||
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 */
|
||||
15 if (! content_type)
|
||||
16 return;
|
||||
17 for (i=0;i<5;++i) {
|
||||
18 if (content_type[i] != text_type[i])
|
||||
19 return;
|
||||
20 }
|
||||
21 appinfo = g_app_info_create_from_commandline ("tfe", "tfe", G_APP_INFO_CREATE_NONE, &err);
|
||||
22 if (err) {
|
||||
23 g_printerr ("%s\n", err->message);
|
||||
24 g_error_free (err);
|
||||
25 return;
|
||||
26 }
|
||||
27 err = NULL;
|
||||
28 file = g_file_new_for_path (g_file_info_get_name (info));
|
||||
29 files = g_list_append (files, file);
|
||||
30 if (! (g_app_info_launch (appinfo, files, NULL, &err))) {
|
||||
31 g_printerr ("%s\n", err->message);
|
||||
32 g_error_free (err);
|
||||
33 }
|
||||
34 g_list_free_full (files, g_object_unref);
|
||||
35 g_object_unref (appinfo);
|
||||
36 }
|
||||
14 #ifdef debug
|
||||
15 g_print ("%s\n", content_type);
|
||||
16 #endif
|
||||
17 if (! content_type)
|
||||
18 return;
|
||||
19 for (i=0;i<5;++i) { /* compare the first 5 characters */
|
||||
20 if (content_type[i] != text_type[i])
|
||||
21 return;
|
||||
22 }
|
||||
23 appinfo = g_app_info_create_from_commandline ("tfe", "tfe", G_APP_INFO_CREATE_NONE, &err);
|
||||
24 if (err) {
|
||||
25 g_printerr ("%s\n", err->message);
|
||||
26 g_error_free (err);
|
||||
27 return;
|
||||
28 }
|
||||
29 err = NULL;
|
||||
30 file = g_file_new_for_path (g_file_info_get_name (info));
|
||||
31 files = g_list_append (files, file);
|
||||
32 if (! (g_app_info_launch (appinfo, files, NULL, &err))) {
|
||||
33 g_printerr ("%s\n", err->message);
|
||||
34 g_error_free (err);
|
||||
35 }
|
||||
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.
|
||||
- 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.
|
||||
You can delete it if unnecessary.
|
||||
- 17-20: If the content type doesn't begin with "text/", then it returns.
|
||||
- 21: Creates GAppInfo object of `tfe` application.
|
||||
If you don't want this, delete or uncomment the definition `#define debug 1` iat line 6 in the source file.
|
||||
- 17-22: If no content type or the content type doesn't begin with "text/",the function returns.
|
||||
- 23: Creates GAppInfo object of `tfe` application.
|
||||
GAppInfo is an interface and the variable `appinfo` points a GDesktopAppInfo instance.
|
||||
GAppInfo is a collection of information of an application.
|
||||
- 30: Launches the application (`tfe`) with an argument `file`.
|
||||
GAppInfo is a collection of information of applications.
|
||||
- 32: Launches the application (`tfe`) with an argument `file`.
|
||||
`g_app_info_launch` has four parameters.
|
||||
The first parameter is GAppInfo object.
|
||||
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.
|
||||
The third parameter is GAppLaunchContext, but this program gives NULL instead.
|
||||
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.
|
||||
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.
|
||||
Such functionality comes from desktop.
|
||||
Such feature comes from desktop.
|
||||
|
||||
## Compilation and execution
|
||||
|
||||
|
@ -511,7 +509,7 @@ The following shows a part of the new ui file (`list5.ui`).
|
|||
<property name="model">
|
||||
<object class="GtkSingleSelection" id="singleselection">
|
||||
<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>
|
||||
</object>
|
||||
</property>
|
||||
|
|
1125
gfm/sec28.md
1125
gfm/sec28.md
File diff suppressed because it is too large
Load diff
321
gfm/sec29.md
321
gfm/sec29.md
|
@ -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
|
||||
|
||||
|
@ -13,11 +13,11 @@ Each column is GtkColumnViewColumn.
|
|||
The property points a GtkSelectionModel object.
|
||||
- Each GtkColumnViewColumn has "factory" property.
|
||||
The property points a GtkListItemFactory (GtkSignalListItemFactory or GtkBuilderListItemFactory).
|
||||
- The factory connects GtkListItem, which belongs to GtkColumnViewColumn, and items of GtkSelectionModel.
|
||||
And the factory builds the descendants widgets of GtkColumnView to display the item on the display.
|
||||
- The factory connects GtkListItem and items of GtkSelectionModel.
|
||||
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.
|
||||
|
||||
The following diagram shows the image how it works.
|
||||
The following diagram shows how it works.
|
||||
|
||||
![ColumnView](../image/column.png)
|
||||
|
||||
|
@ -29,7 +29,7 @@ In addition, the example uses GtkSortListModel and GtkSorter to sort the informa
|
|||
|
||||
## column.ui
|
||||
|
||||
Ui file specifies whole widgets and their structure.
|
||||
Ui file specifies widgets and list item templates.
|
||||
|
||||
~~~xml
|
||||
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>
|
||||
6 <property name="default-height">600</property>
|
||||
7 <child>
|
||||
8 <object class="GtkScrolledWindow" id="scr">
|
||||
8 <object class="GtkScrolledWindow">
|
||||
9 <property name="hexpand">TRUE</property>
|
||||
10 <property name="vexpand">TRUE</property>
|
||||
11 <child>
|
||||
12 <object class="GtkColumnView" id="columnview">
|
||||
13 <property name="model">
|
||||
14 <object class="GtkSingleSelection" id="singleselection">
|
||||
14 <object class="GtkNoSelection">
|
||||
15 <property name="model">
|
||||
16 <object class="GtkSortListModel" id="sortlist">
|
||||
16 <object class="GtkSortListModel">
|
||||
17 <property name="model">
|
||||
18 <object class="GtkDirectoryList" id="directorylist">
|
||||
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>
|
||||
28 </property>
|
||||
29 <child>
|
||||
30 <object class="GtkColumnViewColumn" id="column1">
|
||||
30 <object class="GtkColumnViewColumn">
|
||||
31 <property name="title">Name</property>
|
||||
32 <property name="expand">TRUE</property>
|
||||
33 <property name="factory">
|
||||
|
@ -102,7 +102,7 @@ Ui file specifies whole widgets and their structure.
|
|||
68 </object>
|
||||
69 </property>
|
||||
70 <property name="sorter">
|
||||
71 <object class="GtkStringSorter" id="sorter_name">
|
||||
71 <object class="GtkStringSorter">
|
||||
72 <property name="expression">
|
||||
73 <closure type="gchararray" function="get_file_name">
|
||||
74 </closure>
|
||||
|
@ -112,7 +112,7 @@ Ui file specifies whole widgets and their structure.
|
|||
78 </object>
|
||||
79 </child>
|
||||
80 <child>
|
||||
81 <object class="GtkColumnViewColumn" id="column2">
|
||||
81 <object class="GtkColumnViewColumn">
|
||||
82 <property name="title">Size</property>
|
||||
83 <property name="factory">
|
||||
84 <object class="GtkBuilderListItemFactory">
|
||||
|
@ -125,7 +125,7 @@ Ui file specifies whole widgets and their structure.
|
|||
91 <property name="hexpand">TRUE</property>
|
||||
92 <property name="xalign">0</property>
|
||||
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>
|
||||
96 </closure>
|
||||
97 </binding>
|
||||
|
@ -137,7 +137,7 @@ Ui file specifies whole widgets and their structure.
|
|||
103 </object>
|
||||
104 </property>
|
||||
105 <property name="sorter">
|
||||
106 <object class="GtkNumericSorter" id="sorter_size">
|
||||
106 <object class="GtkNumericSorter">
|
||||
107 <property name="expression">
|
||||
108 <closure type="gint64" function="get_file_size">
|
||||
109 </closure>
|
||||
|
@ -148,7 +148,7 @@ Ui file specifies whole widgets and their structure.
|
|||
114 </object>
|
||||
115 </child>
|
||||
116 <child>
|
||||
117 <object class="GtkColumnViewColumn" id="column3">
|
||||
117 <object class="GtkColumnViewColumn">
|
||||
118 <property name="title">Date modified</property>
|
||||
119 <property name="factory">
|
||||
120 <object class="GtkBuilderListItemFactory">
|
||||
|
@ -173,7 +173,7 @@ Ui file specifies whole widgets and their structure.
|
|||
139 </object>
|
||||
140 </property>
|
||||
141 <property name="sorter">
|
||||
142 <object class="GtkNumericSorter" id="sorter_datetime_modified">
|
||||
142 <object class="GtkNumericSorter">
|
||||
143 <property name="expression">
|
||||
144 <closure type="gint64" function="get_file_unixtime_modified">
|
||||
145 </closure>
|
||||
|
@ -191,18 +191,18 @@ Ui file specifies whole widgets and their structure.
|
|||
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.
|
||||
It points GtkSelectionModel interface.
|
||||
In this ui file, GtkSingleSelection is used as GtkSelectionModel.
|
||||
GtkSingleSelection is an object that implements GtkSelectionModel.
|
||||
GtkNoSelection class is used as GtkSelectionModel.
|
||||
And again, it has "model" property.
|
||||
It points GtkSortListModel.
|
||||
This list model supports sorting the list.
|
||||
It will be explained in the later subsection.
|
||||
And it also has "model" property.
|
||||
It points GtkDirectoryList.
|
||||
Therefore, the chain is: GtkColumnView => GtkSingleSelection => GtkSortListModel => GtkDirectoryList.
|
||||
Therefore, the chain is: GtkColumnView => GtkNoSelection => GtkSortListModel => GtkDirectoryList.
|
||||
- 18-20: GtkDirectoryList.
|
||||
It is a list of GFileInfo, which holds information of files under a directory.
|
||||
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.
|
||||
- 29-79: The first GtkColumnViewColumn object.
|
||||
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.
|
||||
- 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible.
|
||||
(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 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.
|
||||
- 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.
|
||||
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.
|
||||
The function will be explained later.
|
||||
- 80-115: The second GtkColumnViewColumn object.
|
||||
Its "title", "factory" and "sorter" properties are set.
|
||||
GtkNumericSorter is used.
|
||||
Its sorter property is set to GtkNumericSorter.
|
||||
- 116-151: The third GtkColumnViewColumn object.
|
||||
Its "title", "factory" and "sorter" properties are set.
|
||||
GtkNumericSorter is used.
|
||||
Its sorter property is set to GtkNumericSorter.
|
||||
|
||||
## GtkSortListModel and GtkSorter
|
||||
|
||||
GtkSortListModel is a list model that sorts its elements according to a GtkSorter.
|
||||
It has "sorter" property that is set with GtkSorter.
|
||||
GtkSortListModel is a list model that sorts its elements according to a GtkSorter instance assigned to the "sorter" property.
|
||||
The property is bound to "sorter" property of GtkColumnView in line 22 to 24.
|
||||
|
||||
~~~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.
|
||||
|
||||
GtkSorter compares two items (GObject or its descendant).
|
||||
GtkSorter has several child objects.
|
||||
|
||||
- GtkStringSorter compares strings.
|
||||
- GtkNumericSorter compares numbers.
|
||||
- GtkStringSorter compares strings taken from the items.
|
||||
- GtkNumericSorter compares numbers taken from the items.
|
||||
- GtkCustomSorter uses a callback to compare.
|
||||
- GtkMultiSorter combines multiple sorters.
|
||||
|
||||
The example uses GtkStringSorter and GtkNumericSorter.
|
||||
|
||||
GtkStringSorter uses GtkExpression to get the strings from the objects.
|
||||
The GtkExpression is stored in the "expression" property of GtkStringSorter.
|
||||
For example, in the ui file above, the GtkExpression is in the line 71 to 76.
|
||||
GtkStringSorter uses GtkExpression to get the strings from the items (objects).
|
||||
The GtkExpression is stored in the "expression" property of the GtkStringSorter.
|
||||
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
|
||||
<object class="GtkStringSorter" id="sorter_name">
|
||||
<object class="GtkStringSorter">
|
||||
<property name="expression">
|
||||
<closure type="gchararray" function="get_file_name">
|
||||
</closure>
|
||||
|
@ -282,24 +283,23 @@ The GtkExpression calls `get_file_name` function when it is evaluated.
|
|||
~~~C
|
||||
1 char *
|
||||
2 get_file_name (GFileInfo *info) {
|
||||
3 g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
|
||||
4
|
||||
5 return g_strdup(g_file_info_get_name (info));
|
||||
6 }
|
||||
3 return G_IS_FILE_INFO (info) ? g_strdup(g_file_info_get_name (info)) : NULL;
|
||||
4 }
|
||||
~~~
|
||||
|
||||
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 string is owned by `info` so it is necessary to duplicate it.
|
||||
And it returns the copied string.
|
||||
The string will be owned by the expression.
|
||||
|
||||
GtkNumericSorter compares numbers.
|
||||
It is used in the line 106 to 112 and line 142 to 148.
|
||||
The lines from 106 to 112 is:
|
||||
|
||||
~~~xml
|
||||
<object class="GtkNumericSorter" id="sorter_size">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<closure type="gint64" function="get_file_size">
|
||||
</closure>
|
||||
|
@ -313,10 +313,8 @@ The closure tag specifies a callback function `get_file_size`.
|
|||
~~~C
|
||||
1 goffset
|
||||
2 get_file_size (GFileInfo *info) {
|
||||
3 g_return_val_if_fail (G_IS_FILE_INFO (info), -1);
|
||||
4
|
||||
5 return g_file_info_get_size (info);
|
||||
6 }
|
||||
3 return G_IS_FILE_INFO (info) ? g_file_info_get_size (info): -1;
|
||||
4 }
|
||||
~~~
|
||||
|
||||
It just returns the size of `info`.
|
||||
|
@ -340,13 +338,11 @@ The closure tag specifies a callback function `get_file_unixtime_modified`.
|
|||
~~~C
|
||||
1 gint64
|
||||
2 get_file_unixtime_modified (GFileInfo *info) {
|
||||
3 g_return_val_if_fail (G_IS_FILE_INFO (info), -1);
|
||||
3 GDateTime *dt;
|
||||
4
|
||||
5 GDateTime *dt;
|
||||
6
|
||||
7 dt = g_file_info_get_modification_date_time (info);
|
||||
8 return g_date_time_to_unix (dt);
|
||||
9 }
|
||||
5 dt = G_IS_FILE_INFO (info) ? g_file_info_get_modification_date_time (info) : NULL;
|
||||
6 return dt ? g_date_time_to_unix (dt) : -1;
|
||||
7 }
|
||||
~~~
|
||||
|
||||
It gets the modification date and time (GDateTime type) of `info`.
|
||||
|
@ -357,140 +353,106 @@ It returns the unix time (gint64 type).
|
|||
## column.c
|
||||
|
||||
`column.c` is as follows.
|
||||
It is simple and short thanks to `column.ui`.
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 /* functions (closures) for GtkBuilderListItemFactory */
|
||||
4 GIcon *
|
||||
5 get_icon_factory (GtkListItem *item, GFileInfo *info) {
|
||||
6 GIcon *icon;
|
||||
7 if (! G_IS_FILE_INFO (info))
|
||||
8 return NULL;
|
||||
9 else {
|
||||
10 icon = g_file_info_get_icon (info);
|
||||
11 g_object_ref (icon);
|
||||
12 return icon;
|
||||
13 }
|
||||
14 }
|
||||
15
|
||||
16 char *
|
||||
17 get_file_name_factory (GtkListItem *item, GFileInfo *info) {
|
||||
18 if (! G_IS_FILE_INFO (info))
|
||||
19 return NULL;
|
||||
20 else
|
||||
21 return g_strdup (g_file_info_get_name (info));
|
||||
22 }
|
||||
23
|
||||
24 char *
|
||||
25 get_file_size_factory (GtkListItem *item, GFileInfo *info) {
|
||||
26 /* goffset is gint64 */
|
||||
27 goffset size;
|
||||
28
|
||||
29 if (! G_IS_FILE_INFO (info))
|
||||
30 return NULL;
|
||||
31 else {
|
||||
32 size = g_file_info_get_size (info);
|
||||
33 return g_strdup_printf ("%ld", (long int) size);
|
||||
34 }
|
||||
35 }
|
||||
36
|
||||
37 char *
|
||||
38 get_file_time_modified_factory (GtkListItem *item, GFileInfo *info) {
|
||||
39 GDateTime *dt;
|
||||
40
|
||||
41 if (! G_IS_FILE_INFO (info))
|
||||
42 return NULL;
|
||||
43 else {
|
||||
44 dt = g_file_info_get_modification_date_time (info);
|
||||
45 return g_date_time_format (dt, "%F");
|
||||
46 }
|
||||
47 }
|
||||
48
|
||||
49 /* Functions (closures) for GtkSorter */
|
||||
50 char *
|
||||
51 get_file_name (GFileInfo *info) {
|
||||
52 g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
|
||||
53
|
||||
54 return g_strdup(g_file_info_get_name (info));
|
||||
55 }
|
||||
56
|
||||
57 goffset
|
||||
58 get_file_size (GFileInfo *info) {
|
||||
59 g_return_val_if_fail (G_IS_FILE_INFO (info), -1);
|
||||
60
|
||||
61 return g_file_info_get_size (info);
|
||||
62 }
|
||||
63
|
||||
64 gint64
|
||||
65 get_file_unixtime_modified (GFileInfo *info) {
|
||||
66 g_return_val_if_fail (G_IS_FILE_INFO (info), -1);
|
||||
67
|
||||
68 GDateTime *dt;
|
||||
69
|
||||
70 dt = g_file_info_get_modification_date_time (info);
|
||||
71 return g_date_time_to_unix (dt);
|
||||
72 }
|
||||
73
|
||||
74 /* ----- activate, open, startup handlers ----- */
|
||||
75 static void
|
||||
76 app_activate (GApplication *application) {
|
||||
77 GtkApplication *app = GTK_APPLICATION (application);
|
||||
78 GFile *file;
|
||||
79
|
||||
80 GtkBuilder *build = gtk_builder_new_from_resource ("/com/github/ToshioCP/column/column.ui");
|
||||
81 GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
82 GtkDirectoryList *directorylist = GTK_DIRECTORY_LIST (gtk_builder_get_object (build, "directorylist"));
|
||||
83 g_object_unref (build);
|
||||
84
|
||||
85 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
86
|
||||
87 file = g_file_new_for_path (".");
|
||||
88 gtk_directory_list_set_file (directorylist, file);
|
||||
89 g_object_unref (file);
|
||||
90
|
||||
91 gtk_widget_show (win);
|
||||
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
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 /* functions (closures) for GtkBuilderListItemFactory */
|
||||
4 GIcon *
|
||||
5 get_icon_factory (GtkListItem *item, GFileInfo *info) {
|
||||
6 GIcon *icon;
|
||||
7
|
||||
8 /* g_file_info_get_icon can return NULL */
|
||||
9 icon = G_IS_FILE_INFO (info) ? g_file_info_get_icon (info) : NULL;
|
||||
10 return icon ? g_object_ref (icon) : NULL;
|
||||
11 }
|
||||
12
|
||||
13 char *
|
||||
14 get_file_name_factory (GtkListItem *item, GFileInfo *info) {
|
||||
15 return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
|
||||
16 }
|
||||
17
|
||||
18 /* goffset is defined as gint64 */
|
||||
19 /* It is used for file offsets. */
|
||||
20 goffset
|
||||
21 get_file_size_factory (GtkListItem *item, GFileInfo *info) {
|
||||
22 return G_IS_FILE_INFO (info) ? g_file_info_get_size (info) : -1;
|
||||
23 }
|
||||
24
|
||||
25 char *
|
||||
26 get_file_time_modified_factory (GtkListItem *item, GFileInfo *info) {
|
||||
27 GDateTime *dt;
|
||||
28
|
||||
29 /* g_file_info_get_modification_date_time can return NULL */
|
||||
30 dt = G_IS_FILE_INFO (info) ? g_file_info_get_modification_date_time (info) : NULL;
|
||||
31 return dt ? g_date_time_format (dt, "%F") : NULL;
|
||||
32 }
|
||||
33
|
||||
34 /* Functions (closures) for GtkSorter */
|
||||
35 char *
|
||||
36 get_file_name (GFileInfo *info) {
|
||||
37 return G_IS_FILE_INFO (info) ? g_strdup(g_file_info_get_name (info)) : NULL;
|
||||
38 }
|
||||
39
|
||||
40 goffset
|
||||
41 get_file_size (GFileInfo *info) {
|
||||
42 return G_IS_FILE_INFO (info) ? g_file_info_get_size (info): -1;
|
||||
43 }
|
||||
44
|
||||
45 gint64
|
||||
46 get_file_unixtime_modified (GFileInfo *info) {
|
||||
47 GDateTime *dt;
|
||||
48
|
||||
49 dt = G_IS_FILE_INFO (info) ? g_file_info_get_modification_date_time (info) : NULL;
|
||||
50 return dt ? g_date_time_to_unix (dt) : -1;
|
||||
51 }
|
||||
52
|
||||
53 static void
|
||||
54 app_activate (GApplication *application) {
|
||||
55 GtkApplication *app = GTK_APPLICATION (application);
|
||||
56 gtk_window_present (gtk_application_get_active_window(app));
|
||||
57 }
|
||||
58
|
||||
59 static void
|
||||
60 app_startup (GApplication *application) {
|
||||
61 GtkApplication *app = GTK_APPLICATION (application);
|
||||
62 GFile *file;
|
||||
63 GtkBuilder *build = gtk_builder_new_from_resource ("/com/github/ToshioCP/column/column.ui");
|
||||
64 GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
65 GtkDirectoryList *directorylist = GTK_DIRECTORY_LIST (gtk_builder_get_object (build, "directorylist"));
|
||||
66 g_object_unref (build);
|
||||
67
|
||||
68 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
69
|
||||
70 file = g_file_new_for_path (".");
|
||||
71 gtk_directory_list_set_file (directorylist, file);
|
||||
72 g_object_unref (file);
|
||||
73 }
|
||||
74
|
||||
75 #define APPLICATION_ID "com.github.ToshioCP.columnview"
|
||||
76
|
||||
77 int
|
||||
78 main (int argc, char **argv) {
|
||||
79 GtkApplication *app;
|
||||
80 int stat;
|
||||
81
|
||||
82 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
83
|
||||
84 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
85 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
86
|
||||
87 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
88 g_object_unref (app);
|
||||
89 return stat;
|
||||
90 }
|
||||
91
|
||||
~~~
|
||||
|
||||
- 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.
|
||||
|
||||
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.
|
||||
|
||||
~~~
|
||||
|
@ -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.
|
||||
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)
|
||||
|
|
18
gfm/sec3.md
18
gfm/sec3.md
|
@ -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".
|
||||
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.
|
||||
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`
|
||||
~~~
|
||||
|
|
Loading…
Reference in a new issue