Add section 25.
4
.gitignore
vendored
|
@ -24,8 +24,8 @@ src/color/_build
|
||||||
src/turtle/_build
|
src/turtle/_build
|
||||||
src/temp
|
src/temp
|
||||||
src/le
|
src/le
|
||||||
|
src/list4/_build
|
||||||
doc/GFile_example/_build
|
src/list5/_build
|
||||||
html/*
|
html/*
|
||||||
latex/*
|
latex/*
|
||||||
|
|
||||||
|
|
|
@ -38,3 +38,4 @@ You can read it without download.
|
||||||
1. [Combine GtkDrawingArea and TfeTextView](gfm/sec22.md)
|
1. [Combine GtkDrawingArea and TfeTextView](gfm/sec22.md)
|
||||||
1. [Tiny turtle graphics interpreter](gfm/sec23.md)
|
1. [Tiny turtle graphics interpreter](gfm/sec23.md)
|
||||||
1. [GtkListView](gfm/sec24.md)
|
1. [GtkListView](gfm/sec24.md)
|
||||||
|
1. [GtkGridView and activate signal](gfm/sec25.md)
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/* Samples of GFile related objects */
|
|
||||||
/* Copy file program */
|
|
||||||
/* This function uses 'g_input_stream_read' and 'g_output_stream_write'. */
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
usage () {
|
|
||||||
g_printerr ("Usage: copy file1 file2\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAXBUF 4096
|
|
||||||
int
|
|
||||||
main (int argc, char **argv) {
|
|
||||||
GFile *file1, *file2;
|
|
||||||
GFileInputStream *istream;
|
|
||||||
GFileOutputStream *ostream;
|
|
||||||
char buf[MAXBUF];
|
|
||||||
gssize size;
|
|
||||||
GError *err = NULL;
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if (argc != 3)
|
|
||||||
usage();
|
|
||||||
file1 = g_file_new_for_commandline_arg (argv[1]);
|
|
||||||
file2 = g_file_new_for_commandline_arg (argv[2]);
|
|
||||||
if (! (istream = g_file_read (file1, NULL, &err))) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (! (ostream = g_file_replace (file2, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
while ((size = g_input_stream_read (G_INPUT_STREAM (istream), buf, MAXBUF, NULL, &err)) > 0) {
|
|
||||||
if ((size = g_output_stream_write (G_OUTPUT_STREAM (ostream), buf, (gsize) size, NULL, &err)) < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (size < 0) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
status = 1;
|
|
||||||
}
|
|
||||||
if (! (g_input_stream_close (G_INPUT_STREAM (istream), NULL, &err))) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
status = 1;
|
|
||||||
}
|
|
||||||
if (! (g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, &err))) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
status = 1;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/* Samples of GFile related objects */
|
|
||||||
/* Copy file program */
|
|
||||||
/* This function uses 'g_input_stream_read' and 'g_output_stream_write'. */
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
usage () {
|
|
||||||
g_printerr ("Usage: gfile_object (file|uri)\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv) {
|
|
||||||
GFile *file;
|
|
||||||
GType type;
|
|
||||||
|
|
||||||
if (argc != 2)
|
|
||||||
usage();
|
|
||||||
file = g_file_new_for_commandline_arg (argv[1]);
|
|
||||||
type = G_OBJECT_TYPE (file);
|
|
||||||
g_print ("%s\n", g_type_name (type));
|
|
||||||
while (type = g_type_parent (type))
|
|
||||||
g_print ("%s\n", g_type_name (type));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
project('gio_samples', 'c')
|
|
||||||
|
|
||||||
compiler = meson.get_compiler('c')
|
|
||||||
|
|
||||||
giodep = dependency('gio-2.0')
|
|
||||||
|
|
||||||
executable('readline', 'readline.c', dependencies: giodep, install: false)
|
|
||||||
executable('copy', 'copy.c', dependencies: giodep, install: false)
|
|
||||||
executable('gfile_object', 'gfile_object.c', dependencies: giodep, install: false)
|
|
||||||
|
|
||||||
run_command('ruby', '../../src2md.rb', 'readme.src.md', 'readme.md')
|
|
|
@ -1,84 +0,0 @@
|
||||||
/* Samples of GFile related objects */
|
|
||||||
/* Functions here has "sgf" prefix. Sgf is an acronym of "Sample of GFile". */
|
|
||||||
|
|
||||||
/* List a file */
|
|
||||||
/* This program shows how to read lines from a file. */
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <glib/gprintf.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
usage () {
|
|
||||||
g_printerr ("Usage: readline file\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inputstream objects */
|
|
||||||
/* GInputStream */
|
|
||||||
/* +----- GFileInputStream */
|
|
||||||
/* +--+-- GFilterInputStream */
|
|
||||||
/* +--+-- GBufferedInputStream */
|
|
||||||
/* +----- GDataInputStream */
|
|
||||||
|
|
||||||
GDataInputStream *
|
|
||||||
sgf_open (GFile *file) {
|
|
||||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
|
||||||
|
|
||||||
GFileInputStream *stream;
|
|
||||||
GDataInputStream *dstream;
|
|
||||||
GError *err;
|
|
||||||
|
|
||||||
if (! (stream = g_file_read (file, NULL, &err))) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* 'dstream' is a different instance from 'stream' instance. */
|
|
||||||
/* 'dstream' has "base-stream" property, which is a property of GFilterInputStream, and the property points 'stream'. */
|
|
||||||
/* GBufferedInputStream uses base-stream to read (input) data from its source. */
|
|
||||||
/* Therefore, 'dstream' reads a line through the IO interface of 'stream'. */
|
|
||||||
dstream = g_data_input_stream_new (G_INPUT_STREAM (stream));
|
|
||||||
return dstream;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
sgf_readline (GDataInputStream *dstream) {
|
|
||||||
char *contents;
|
|
||||||
gsize length;
|
|
||||||
GError *err = NULL;
|
|
||||||
|
|
||||||
contents = g_data_input_stream_read_line_utf8 (dstream, &length, NULL, &err);
|
|
||||||
if (! contents && err) {
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return contents; /* if contents == NULL, then it is EOF */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sgf_close (GDataInputStream *dstream) {
|
|
||||||
GError *err = NULL;
|
|
||||||
|
|
||||||
/* At the same time dstream closes, its base stream (GFileInputStream created by 'sgf_open') is also closed. */
|
|
||||||
/* Because the default of "close-base-stream" property (of GFilterInputStream which is an ancester of GDataInputStream) is TRUE */
|
|
||||||
if (! g_input_stream_close (G_INPUT_STREAM (dstream), NULL, &err))
|
|
||||||
g_warning ("%s\n", err->message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----- main ----- */
|
|
||||||
int
|
|
||||||
main (int argc, char **argv) {
|
|
||||||
GFile *file;
|
|
||||||
GDataInputStream *dstream;
|
|
||||||
char *line;
|
|
||||||
|
|
||||||
if (argc != 2)
|
|
||||||
usage ();
|
|
||||||
file = g_file_new_for_commandline_arg (argv[1]);
|
|
||||||
if (! (dstream = sgf_open (file)))
|
|
||||||
return -1; /* error */
|
|
||||||
while (line = sgf_readline (dstream))
|
|
||||||
g_printf ("%s\n", line);
|
|
||||||
sgf_close (dstream);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
# What are the files in this directory?
|
|
||||||
|
|
||||||
They are examples to show how to use GFile related objects such as GInputStream and GOutPutStream.
|
|
||||||
|
|
||||||
- `meson.build` is used by meson.
|
|
||||||
- `readline.c` is an example to show how to read lines from a file.
|
|
||||||
- `copy.c` is an example to show read and write stream functions with Gio objects.
|
|
||||||
- `gfile_object.c` shows the object implements GFile interface.
|
|
||||||
|
|
||||||
## Compilation
|
|
||||||
|
|
||||||
Type as follows on your command line.
|
|
||||||
|
|
||||||
1. `meson _build`
|
|
||||||
2. `ninja -C _build`
|
|
||||||
|
|
||||||
Then executable files `readline`, `copy` and `gfile_object` are created under `_build` directory.
|
|
||||||
|
|
||||||
## Execution
|
|
||||||
|
|
||||||
Readline prints the contents of a file.
|
|
||||||
The file is given to `readline` as an argument.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/readline readline.c
|
|
||||||
/* Samples of GFile related objects */
|
|
||||||
/* Functions here has "sgf" prefix. Sgf is an acronym of "Sample of GFile". */
|
|
||||||
|
|
||||||
/* List a file */
|
|
||||||
/* This program shows how to read lines from a file. */
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
usage () {
|
|
||||||
g_printerr ("Usage: readline file\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
... ... ...
|
|
||||||
... ... ...
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Readline can also prints a file through the internet.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/readline http://www7b.biglobe.ne.jp/~j87107/SINU/index.html
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
||||||
|
|
||||||
... ... ...
|
|
||||||
... ... ...
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This is because GFile can be constructed for local path or uri.
|
|
||||||
|
|
||||||
Copy is given two arguments.
|
|
||||||
The first one is a source filename and the second one is a destination filename.
|
|
||||||
If the destination file is exist, it will be overwritten.
|
|
||||||
Before the overwriting, the destination file is backed up.
|
|
||||||
The backup file name is appended with tilde ('~').
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ ls
|
|
||||||
_build copy.c meson.build readline.c readme.md
|
|
||||||
$ _build/copy copy.c sample.txt
|
|
||||||
$ ls
|
|
||||||
_build copy.c meson.build readline.c readme.md sample.txt
|
|
||||||
$ diff copy.c sample.txt
|
|
||||||
$ _build/copy readline.c sample.txt
|
|
||||||
$ ls
|
|
||||||
_build copy.c meson.build readline.c readme.md sample.txt sample.txt~
|
|
||||||
$ diff readline.c sample.txt
|
|
||||||
$ diff copy.c sample.txt~
|
|
||||||
$
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Files can be on the internet.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/copy http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf algebra.pdf
|
|
||||||
$ ls
|
|
||||||
_build algebra.pdf copy.c meson.build readline.c readme.md sample.txt sample.txt~
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Gfile_object shows the object implements GFile interface.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/gfile_object gfile_object.c
|
|
||||||
GLocalFile
|
|
||||||
GObject
|
|
||||||
$ _build/gfile_object http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf
|
|
||||||
GDaemonFile
|
|
||||||
GObject
|
|
||||||
~~~
|
|
||||||
|
|
||||||
`g_file_new_for_path` creates GLocalFile object which implements GFile interface.
|
|
||||||
And it returns the pointer to the object as `GFile *`.
|
|
||||||
`g_file_new_for_uri` creates GDaemonFile object which implements GFile interface.
|
|
||||||
And it returns the pointer to the object as `GFile *`.
|
|
||||||
|
|
||||||
## GFile interface
|
|
||||||
|
|
||||||
GFile is an interface.
|
|
||||||
It is like a pathname.
|
|
||||||
|
|
||||||
If you want to read from a file or write to a file, you need to create a stream object.
|
|
||||||
`copy.c` creates GInputStream and GOutputStream to copy a file.
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
1 /* Samples of GFile related objects */
|
|
||||||
2 /* Copy file program */
|
|
||||||
3 /* This function uses 'g_input_stream_read' and 'g_output_stream_write'. */
|
|
||||||
4
|
|
||||||
5 #include <gio/gio.h>
|
|
||||||
6
|
|
||||||
7 void
|
|
||||||
8 usage () {
|
|
||||||
9 g_printerr ("Usage: copy file1 file2\n");
|
|
||||||
10 exit (1);
|
|
||||||
11 }
|
|
||||||
12
|
|
||||||
13 #define MAXBUF 4096
|
|
||||||
14 int
|
|
||||||
15 main (int argc, char **argv) {
|
|
||||||
16 GFile *file1, *file2;
|
|
||||||
17 GFileInputStream *istream;
|
|
||||||
18 GFileOutputStream *ostream;
|
|
||||||
19 char buf[MAXBUF];
|
|
||||||
20 gssize size;
|
|
||||||
21 GError *err = NULL;
|
|
||||||
22 int status = 0;
|
|
||||||
23
|
|
||||||
24 if (argc != 3)
|
|
||||||
25 usage();
|
|
||||||
26 file1 = g_file_new_for_commandline_arg (argv[1]);
|
|
||||||
27 file2 = g_file_new_for_commandline_arg (argv[2]);
|
|
||||||
28 if (! (istream = g_file_read (file1, NULL, &err))) {
|
|
||||||
29 g_warning ("%s\n", err->message);
|
|
||||||
30 return 1;
|
|
||||||
31 }
|
|
||||||
32 if (! (ostream = g_file_replace (file2, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) {
|
|
||||||
33 g_warning ("%s\n", err->message);
|
|
||||||
34 return 1;
|
|
||||||
35 }
|
|
||||||
36 while ((size = g_input_stream_read (G_INPUT_STREAM (istream), buf, MAXBUF, NULL, &err)) > 0) {
|
|
||||||
37 if ((size = g_output_stream_write (G_OUTPUT_STREAM (ostream), buf, (gsize) size, NULL, &err)) < 0)
|
|
||||||
38 break;
|
|
||||||
39 }
|
|
||||||
40 if (size < 0) {
|
|
||||||
41 g_warning ("%s\n", err->message);
|
|
||||||
42 status = 1;
|
|
||||||
43 }
|
|
||||||
44 if (! (g_input_stream_close (G_INPUT_STREAM (istream), NULL, &err))) {
|
|
||||||
45 g_warning ("%s\n", err->message);
|
|
||||||
46 status = 1;
|
|
||||||
47 }
|
|
||||||
48 if (! (g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, &err))) {
|
|
||||||
49 g_warning ("%s\n", err->message);
|
|
||||||
50 status = 1;
|
|
||||||
51 }
|
|
||||||
52 return status;
|
|
||||||
53 }
|
|
||||||
54
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## Stream objects
|
|
||||||
|
|
||||||
Stream objects have hierarchy.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
GInputStream
|
|
||||||
+--+-- GFilterInputStream
|
|
||||||
| +--+-- GBufferedInputStream
|
|
||||||
| | +----- GDataInputStream
|
|
||||||
| +----- GConverterInputStream
|
|
||||||
+----- GFileInputStream
|
|
||||||
+----- GMemoryInputStream
|
|
||||||
+----- GUnixInputStream
|
|
||||||
~~~
|
|
||||||
|
|
||||||
GInputStream is the top parent object.
|
|
||||||
It is an abstract object.
|
|
||||||
Streams are created with specific objects such as files, memories and unix file descriptors.
|
|
||||||
For example, the following function creates a GFileInputStream.
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
GFileInputStream *istream = g_file_read (GFile *file, GCancellable *cancellable, GError **error);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This stream is a child of GInputStream object, so you can apply any functions of GInputStream for `istream`.
|
|
||||||
For example,
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
gssize size = g_input_stream_read (G_INPUT_STREAM (istream), void *buffer, gsize count, GCancellable *cancellable, GError **error);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This function reads data from `istream` and puts them into `buffer`.
|
|
||||||
|
|
||||||
GDataInputStream is used often.
|
|
||||||
It can read structured data such as sized data (byte, int16, int32 and int64) and lines (new line terminated string).
|
|
||||||
For example,
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
GDataInputStream *dstream = g_data_input_stream_new (G_INPUT_STREAM (istream));
|
|
||||||
char *line = g_data_input_stream_read_line_utf8 (dstream, gsize *size, GCancellable *cancellable, GError **error);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
The program above reads a line from `dstream`.
|
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
# What are the files in this directory?
|
|
||||||
|
|
||||||
They are examples to show how to use GFile related objects such as GInputStream and GOutPutStream.
|
|
||||||
|
|
||||||
- `meson.build` is used by meson.
|
|
||||||
- `readline.c` is an example to show how to read lines from a file.
|
|
||||||
- `copy.c` is an example to show read and write stream functions with Gio objects.
|
|
||||||
- `gfile_object.c` shows the object implements GFile interface.
|
|
||||||
|
|
||||||
## Compilation
|
|
||||||
|
|
||||||
Type as follows on your command line.
|
|
||||||
|
|
||||||
1. `meson _build`
|
|
||||||
2. `ninja -C _build`
|
|
||||||
|
|
||||||
Then executable files `readline`, `copy` and `gfile_object` are created under `_build` directory.
|
|
||||||
|
|
||||||
## Execution
|
|
||||||
|
|
||||||
Readline prints the contents of a file.
|
|
||||||
The file is given to `readline` as an argument.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/readline readline.c
|
|
||||||
/* Samples of GFile related objects */
|
|
||||||
/* Functions here has "sgf" prefix. Sgf is an acronym of "Sample of GFile". */
|
|
||||||
|
|
||||||
/* List a file */
|
|
||||||
/* This program shows how to read lines from a file. */
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
usage () {
|
|
||||||
g_printerr ("Usage: readline file\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
... ... ...
|
|
||||||
... ... ...
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Readline can also prints a file through the internet.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/readline http://www7b.biglobe.ne.jp/~j87107/SINU/index.html
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
||||||
|
|
||||||
... ... ...
|
|
||||||
... ... ...
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This is because GFile can be constructed for local path or uri.
|
|
||||||
|
|
||||||
Copy is given two arguments.
|
|
||||||
The first one is a source filename and the second one is a destination filename.
|
|
||||||
If the destination file is exist, it will be overwritten.
|
|
||||||
Before the overwriting, the destination file is backed up.
|
|
||||||
The backup file name is appended with tilde ('~').
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ ls
|
|
||||||
_build copy.c meson.build readline.c readme.md
|
|
||||||
$ _build/copy copy.c sample.txt
|
|
||||||
$ ls
|
|
||||||
_build copy.c meson.build readline.c readme.md sample.txt
|
|
||||||
$ diff copy.c sample.txt
|
|
||||||
$ _build/copy readline.c sample.txt
|
|
||||||
$ ls
|
|
||||||
_build copy.c meson.build readline.c readme.md sample.txt sample.txt~
|
|
||||||
$ diff readline.c sample.txt
|
|
||||||
$ diff copy.c sample.txt~
|
|
||||||
$
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Files can be on the internet.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/copy http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf algebra.pdf
|
|
||||||
$ ls
|
|
||||||
_build algebra.pdf copy.c meson.build readline.c readme.md sample.txt sample.txt~
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Gfile_object shows the object implements GFile interface.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
$ _build/gfile_object gfile_object.c
|
|
||||||
GLocalFile
|
|
||||||
GObject
|
|
||||||
$ _build/gfile_object http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf
|
|
||||||
GDaemonFile
|
|
||||||
GObject
|
|
||||||
~~~
|
|
||||||
|
|
||||||
`g_file_new_for_path` creates GLocalFile object which implements GFile interface.
|
|
||||||
And it returns the pointer to the object as `GFile *`.
|
|
||||||
`g_file_new_for_uri` creates GDaemonFile object which implements GFile interface.
|
|
||||||
And it returns the pointer to the object as `GFile *`.
|
|
||||||
|
|
||||||
## GFile interface
|
|
||||||
|
|
||||||
GFile is an interface.
|
|
||||||
It is like a pathname.
|
|
||||||
|
|
||||||
If you want to read from a file or write to a file, you need to create a stream object.
|
|
||||||
`copy.c` creates GInputStream and GOutputStream to copy a file.
|
|
||||||
|
|
||||||
@@@include
|
|
||||||
copy.c
|
|
||||||
@@@
|
|
||||||
|
|
||||||
## Stream objects
|
|
||||||
|
|
||||||
Stream objects have hierarchy.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
GInputStream
|
|
||||||
+--+-- GFilterInputStream
|
|
||||||
| +--+-- GBufferedInputStream
|
|
||||||
| | +----- GDataInputStream
|
|
||||||
| +----- GConverterInputStream
|
|
||||||
+----- GFileInputStream
|
|
||||||
+----- GMemoryInputStream
|
|
||||||
+----- GUnixInputStream
|
|
||||||
~~~
|
|
||||||
|
|
||||||
GInputStream is the top parent object.
|
|
||||||
It is an abstract object.
|
|
||||||
Streams are created with specific objects such as files, memories and unix file descriptors.
|
|
||||||
For example, the following function creates a GFileInputStream.
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
GFileInputStream *istream = g_file_read (GFile *file, GCancellable *cancellable, GError **error);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This stream is a child of GInputStream object, so you can apply any functions of GInputStream for `istream`.
|
|
||||||
For example,
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
gssize size = g_input_stream_read (G_INPUT_STREAM (istream), void *buffer, gsize count, GCancellable *cancellable, GError **error);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This function reads data from `istream` and puts them into `buffer`.
|
|
||||||
|
|
||||||
GDataInputStream is used often.
|
|
||||||
It can read structured data such as sized data (byte, int16, int32 and int64) and lines (new line terminated string).
|
|
||||||
For example,
|
|
||||||
|
|
||||||
~~~C
|
|
||||||
GDataInputStream *dstream = g_data_input_stream_new (G_INPUT_STREAM (istream));
|
|
||||||
char *line = g_data_input_stream_read_line_utf8 (dstream, gsize *size, GCancellable *cancellable, GError **error);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
The program above reads a line from `dstream`.
|
|
||||||
|
|
71
gfm/sec24.md
|
@ -1,4 +1,4 @@
|
||||||
Up: [Readme.md](../Readme.md), Prev: [Section 23](sec23.md)
|
Up: [Readme.md](../Readme.md), Prev: [Section 23](sec23.md), Next: [Section 25](sec25.md)
|
||||||
|
|
||||||
# GtkListView
|
# GtkListView
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ GtkNoSelection is used, so user can't select any item.
|
||||||
30
|
30
|
||||||
31 /* ----- activate, open, startup handlers ----- */
|
31 /* ----- activate, open, startup handlers ----- */
|
||||||
32 static void
|
32 static void
|
||||||
33 tfe_activate (GApplication *application) {
|
33 app_activate (GApplication *application) {
|
||||||
34 GtkApplication *app = GTK_APPLICATION (application);
|
34 GtkApplication *app = GTK_APPLICATION (application);
|
||||||
35 GtkWidget *win = gtk_application_window_new (app);
|
35 GtkWidget *win = gtk_application_window_new (app);
|
||||||
36 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
36 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||||
|
@ -175,7 +175,7 @@ GtkNoSelection is used, so user can't select any item.
|
||||||
55 }
|
55 }
|
||||||
56
|
56
|
||||||
57 static void
|
57 static void
|
||||||
58 tfe_startup (GApplication *application) {
|
58 app_startup (GApplication *application) {
|
||||||
59 }
|
59 }
|
||||||
60
|
60
|
||||||
61 /* ----- main ----- */
|
61 /* ----- main ----- */
|
||||||
|
@ -186,8 +186,8 @@ GtkNoSelection is used, so user can't select any item.
|
||||||
66
|
66
|
||||||
67 app = gtk_application_new ("com.github.ToshioCP.list1", G_APPLICATION_FLAGS_NONE);
|
67 app = gtk_application_new ("com.github.ToshioCP.list1", G_APPLICATION_FLAGS_NONE);
|
||||||
68
|
68
|
||||||
69 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
69 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
70 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
70 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
71
|
71
|
||||||
72 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
72 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
73 g_object_unref (app);
|
73 g_object_unref (app);
|
||||||
|
@ -260,7 +260,7 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
|
||||||
2
|
2
|
||||||
3 /* ----- activate, open, startup handlers ----- */
|
3 /* ----- activate, open, startup handlers ----- */
|
||||||
4 static void
|
4 static void
|
||||||
5 tfe_activate (GApplication *application) {
|
5 app_activate (GApplication *application) {
|
||||||
6 GtkApplication *app = GTK_APPLICATION (application);
|
6 GtkApplication *app = GTK_APPLICATION (application);
|
||||||
7 GtkWidget *win = gtk_application_window_new (app);
|
7 GtkWidget *win = gtk_application_window_new (app);
|
||||||
8 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
8 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||||
|
@ -297,7 +297,7 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
|
||||||
39 }
|
39 }
|
||||||
40
|
40
|
||||||
41 static void
|
41 static void
|
||||||
42 tfe_startup (GApplication *application) {
|
42 app_startup (GApplication *application) {
|
||||||
43 }
|
43 }
|
||||||
44
|
44
|
||||||
45 /* ----- main ----- */
|
45 /* ----- main ----- */
|
||||||
|
@ -308,8 +308,8 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
|
||||||
50
|
50
|
||||||
51 app = gtk_application_new ("com.github.ToshioCP.list2", G_APPLICATION_FLAGS_NONE);
|
51 app = gtk_application_new ("com.github.ToshioCP.list2", G_APPLICATION_FLAGS_NONE);
|
||||||
52
|
52
|
||||||
53 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
53 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
54 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
54 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
55
|
55
|
||||||
56 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
56 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
57 g_object_unref (app);
|
57 g_object_unref (app);
|
||||||
|
@ -424,7 +424,7 @@ The program is located in [src/misc](../src/misc) directory.
|
||||||
10
|
10
|
||||||
11 /* ----- activate, open, startup handlers ----- */
|
11 /* ----- activate, open, startup handlers ----- */
|
||||||
12 static void
|
12 static void
|
||||||
13 tfe_activate (GApplication *application) {
|
13 app_activate (GApplication *application) {
|
||||||
14 GtkApplication *app = GTK_APPLICATION (application);
|
14 GtkApplication *app = GTK_APPLICATION (application);
|
||||||
15 GtkWidget *win = gtk_application_window_new (app);
|
15 GtkWidget *win = gtk_application_window_new (app);
|
||||||
16 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
16 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||||
|
@ -455,31 +455,30 @@ The program is located in [src/misc](../src/misc) directory.
|
||||||
41 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
|
41 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
|
||||||
42
|
42
|
||||||
43 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
43 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
||||||
44 gtk_list_view_set_enable_rubberband (GTK_LIST_VIEW (lv), TRUE);
|
44 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||||
45 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
45 gtk_widget_show (win);
|
||||||
46 gtk_widget_show (win);
|
46 }
|
||||||
47 }
|
47
|
||||||
48
|
48 static void
|
||||||
49 static void
|
49 app_startup (GApplication *application) {
|
||||||
50 tfe_startup (GApplication *application) {
|
50 }
|
||||||
51 }
|
51
|
||||||
52
|
52 /* ----- main ----- */
|
||||||
53 /* ----- main ----- */
|
53 int
|
||||||
54 int
|
54 main (int argc, char **argv) {
|
||||||
55 main (int argc, char **argv) {
|
55 GtkApplication *app;
|
||||||
56 GtkApplication *app;
|
56 int stat;
|
||||||
57 int stat;
|
57
|
||||||
58
|
58 app = gtk_application_new ("com.github.ToshioCP.list3", G_APPLICATION_FLAGS_NONE);
|
||||||
59 app = gtk_application_new ("com.github.ToshioCP.list2", G_APPLICATION_FLAGS_NONE);
|
59
|
||||||
60
|
60 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
61 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
61 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
62 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
62
|
||||||
63
|
63 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
64 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
64 g_object_unref (app);
|
||||||
65 g_object_unref (app);
|
65 return stat;
|
||||||
66 return stat;
|
66 }
|
||||||
67 }
|
67
|
||||||
68
|
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Compile and execute it.
|
Compile and execute it.
|
||||||
|
@ -493,4 +492,4 @@ $ ./a.out
|
||||||
![screenshot list3](../image/list3.png)
|
![screenshot list3](../image/list3.png)
|
||||||
|
|
||||||
|
|
||||||
Up: [Readme.md](../Readme.md), Prev: [Section 23](sec23.md)
|
Up: [Readme.md](../Readme.md), Prev: [Section 23](sec23.md), Next: [Section 25](sec25.md)
|
||||||
|
|
564
gfm/sec25.md
Normal file
|
@ -0,0 +1,564 @@
|
||||||
|
Up: [Readme.md](../Readme.md), Prev: [Section 24](sec24.md)
|
||||||
|
|
||||||
|
# GtkGridView and activate signal
|
||||||
|
|
||||||
|
GtkGridView is similar to GtkListView.
|
||||||
|
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.
|
||||||
|
|
||||||
|
In this section, let's make a very simple file browser `list4`.
|
||||||
|
It just shows the files in the current directory.
|
||||||
|
And a user can choose list or grid by clicking on buttons in the tool bar.
|
||||||
|
Each item in the list or grid has an icon and a filename.
|
||||||
|
In addition, `list4` provides the way to open the `tfe` text editor to show a text file.
|
||||||
|
A user can do that by double clicking on an item or pressing enter key when an item is selected.
|
||||||
|
|
||||||
|
## GtkDirectoryList
|
||||||
|
|
||||||
|
GtkDirectoryList implements GListModel and it contains information of files in a certain directory.
|
||||||
|
The items of the list are GFileInfo objects.
|
||||||
|
|
||||||
|
In the `list4` source files, GtkDirectoryList is described in a ui file and built by GtkBuilder.
|
||||||
|
It is referenced to by a GtkSingleSelection model and the GtkSingleSelection model is referenced to by a GListView or GGridView object.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
GtkListView (model property) => GtkSingleSelection (model property) => GtkDirectoryList
|
||||||
|
GtkGridView (model property) => GtkSingleSelection (model property) => GtkDirectoryList
|
||||||
|
~~~
|
||||||
|
|
||||||
|
![DirectoryList](../image/directorylist.png)
|
||||||
|
|
||||||
|
The part of the ui file `list4.ui` is as follows.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
<object class="GtkListView" id="list">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkSingleSelection" id="singleselection">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkDirectoryList" id="directorylist">
|
||||||
|
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkGridView" id="grid">
|
||||||
|
<property name="model">singleselection</property>
|
||||||
|
</object>
|
||||||
|
~~~
|
||||||
|
|
||||||
|
GtkDirectoryList has an "attributes" property.
|
||||||
|
It is attributes of GFileInfo such as "standard::name", "standard::icon" and "standard::content-type".
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
2 <interface>
|
||||||
|
3 <object class="GtkApplicationWindow" id="win">
|
||||||
|
4 <property name="title">file list</property>
|
||||||
|
5 <property name="default-width">600</property>
|
||||||
|
6 <property name="default-height">400</property>
|
||||||
|
7 <child>
|
||||||
|
8 <object class="GtkBox" id="boxv">
|
||||||
|
9 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
10 <child>
|
||||||
|
11 <object class="GtkBox" id="boxh">
|
||||||
|
12 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
13 <child>
|
||||||
|
14 <object class="GtkLabel" id="dmy1">
|
||||||
|
15 <property name="hexpand">TRUE</property>
|
||||||
|
16 </object>
|
||||||
|
17 </child>
|
||||||
|
18 <child>
|
||||||
|
19 <object class="GtkButton" id="btnlist">
|
||||||
|
20 <property name="name">btnlist</property>
|
||||||
|
21 <property name="action-name">win.view</property>
|
||||||
|
22 <property name="action-target">'list'</property>
|
||||||
|
23 <child>
|
||||||
|
24 <object class="GtkImage">
|
||||||
|
25 <property name="resource">/com/github/ToshioCP/list4/list.png</property>
|
||||||
|
26 </object>
|
||||||
|
27 </child>
|
||||||
|
28 </object>
|
||||||
|
29 </child>
|
||||||
|
30 <child>
|
||||||
|
31 <object class="GtkButton" id="btngrid">
|
||||||
|
32 <property name="name">btngrid</property>
|
||||||
|
33 <property name="action-name">win.view</property>
|
||||||
|
34 <property name="action-target">'grid'</property>
|
||||||
|
35 <child>
|
||||||
|
36 <object class="GtkImage">
|
||||||
|
37 <property name="resource">/com/github/ToshioCP/list4/grid.png</property>
|
||||||
|
38 </object>
|
||||||
|
39 </child>
|
||||||
|
40 </object>
|
||||||
|
41 </child>
|
||||||
|
42 <child>
|
||||||
|
43 <object class="GtkLabel" id="dmy2">
|
||||||
|
44 <property name="width-chars">10</property>
|
||||||
|
45 </object>
|
||||||
|
46 </child>
|
||||||
|
47 </object>
|
||||||
|
48 </child>
|
||||||
|
49 <child>
|
||||||
|
50 <object class="GtkScrolledWindow" id="scr">
|
||||||
|
51 <property name="hexpand">TRUE</property>
|
||||||
|
52 <property name="vexpand">TRUE</property>
|
||||||
|
53 </object>
|
||||||
|
54 </child>
|
||||||
|
55 </object>
|
||||||
|
56 </child>
|
||||||
|
57 </object>
|
||||||
|
58 <object class="GtkListView" id="list">
|
||||||
|
59 <property name="model">
|
||||||
|
60 <object class="GtkSingleSelection" id="singleselection">
|
||||||
|
61 <property name="model">
|
||||||
|
62 <object class="GtkDirectoryList" id="directorylist">
|
||||||
|
63 <property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
64 </object>
|
||||||
|
65 </property>
|
||||||
|
66 </object>
|
||||||
|
67 </property>
|
||||||
|
68 </object>
|
||||||
|
69 <object class="GtkGridView" id="grid">
|
||||||
|
70 <property name="model">singleselection</property>
|
||||||
|
71 </object>
|
||||||
|
72 </interface>
|
||||||
|
73
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The file consists of two parts.
|
||||||
|
The first part begins at the third line and ends at the 57th line.
|
||||||
|
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.
|
||||||
|
This is 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`.
|
||||||
|
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.
|
||||||
|
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 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.
|
||||||
|
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.
|
||||||
|
The action name is "win.view" and the target is "list".
|
||||||
|
Generally, a target is GVariant, which can be string, integer, float and so on.
|
||||||
|
You need to use GVariant text format to write GVariant value in ui files.
|
||||||
|
If the type of the GVarinat value is string, then the value with GVariant text format is bounded by single quotes or double quotes.
|
||||||
|
Because ui file is xml format text, single quote cannot be written without escape.
|
||||||
|
Its escape sequence is \'.
|
||||||
|
Therefore, the target 'list' is written as \'list\'.
|
||||||
|
Because the button is connected to the action, "clicked" signal handler isn't needed.
|
||||||
|
- 23-27: The child widget of the button is GtkImage.
|
||||||
|
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.
|
||||||
|
|
||||||
|
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));
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The signal handler `view_activated` will be explained later.
|
||||||
|
|
||||||
|
## Factories
|
||||||
|
|
||||||
|
Each view (GtkListView and GtkGridView) has its own factory because its items have different structure of widgets.
|
||||||
|
The factories are GtkBuilderListItemFactory objects.
|
||||||
|
Their ui files are as follows.
|
||||||
|
|
||||||
|
factory_list.ui
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
2 <interface>
|
||||||
|
3 <template class="GtkListItem">
|
||||||
|
4 <property name="child">
|
||||||
|
5 <object class="GtkBox">
|
||||||
|
6 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
7 <property name="spacing">20</property>
|
||||||
|
8 <child>
|
||||||
|
9 <object class="GtkImage">
|
||||||
|
10 <binding name="gicon">
|
||||||
|
11 <closure type="GIcon" function="get_icon">
|
||||||
|
12 <lookup name="item">GtkListItem</lookup>
|
||||||
|
13 </closure>
|
||||||
|
14 </binding>
|
||||||
|
15 </object>
|
||||||
|
16 </child>
|
||||||
|
17 <child>
|
||||||
|
18 <object class="GtkLabel">
|
||||||
|
19 <property name="hexpand">TRUE</property>
|
||||||
|
20 <property name="xalign">0</property>
|
||||||
|
21 <binding name="label">
|
||||||
|
22 <closure type="gchararray" function="get_file_name">
|
||||||
|
23 <lookup name="item">GtkListItem</lookup>
|
||||||
|
24 </closure>
|
||||||
|
25 </binding>
|
||||||
|
26 </object>
|
||||||
|
27 </child>
|
||||||
|
28 </object>
|
||||||
|
29 </property>
|
||||||
|
30 </template>
|
||||||
|
31 </interface>
|
||||||
|
32
|
||||||
|
~~~
|
||||||
|
|
||||||
|
factory_grid.ui
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
2 <interface>
|
||||||
|
3 <template class="GtkListItem">
|
||||||
|
4 <property name="child">
|
||||||
|
5 <object class="GtkBox">
|
||||||
|
6 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
7 <property name="spacing">20</property>
|
||||||
|
8 <child>
|
||||||
|
9 <object class="GtkImage">
|
||||||
|
10 <property name="icon-size">GTK_ICON_SIZE_LARGE</property>
|
||||||
|
11 <binding name="gicon">
|
||||||
|
12 <closure type="GIcon" function="get_icon">
|
||||||
|
13 <lookup name="item">GtkListItem</lookup>
|
||||||
|
14 </closure>
|
||||||
|
15 </binding>
|
||||||
|
16 </object>
|
||||||
|
17 </child>
|
||||||
|
18 <child>
|
||||||
|
19 <object class="GtkLabel">
|
||||||
|
20 <property name="hexpand">TRUE</property>
|
||||||
|
21 <property name="xalign">0.5</property>
|
||||||
|
22 <binding name="label">
|
||||||
|
23 <closure type="gchararray" function="get_file_name">
|
||||||
|
24 <lookup name="item">GtkListItem</lookup>
|
||||||
|
25 </closure>
|
||||||
|
26 </binding>
|
||||||
|
27 </object>
|
||||||
|
28 </child>
|
||||||
|
29 </object>
|
||||||
|
30 </property>
|
||||||
|
31 </template>
|
||||||
|
32 </interface>
|
||||||
|
33
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The two files above are almost same.
|
||||||
|
The difference is:
|
||||||
|
|
||||||
|
- The orientation of the box
|
||||||
|
- The icon size
|
||||||
|
- The position of the text of the label
|
||||||
|
|
||||||
|
~~~
|
||||||
|
$ cd list4; diff factory_list.ui factory_grid.ui
|
||||||
|
6c6
|
||||||
|
< <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
---
|
||||||
|
> <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
9a10
|
||||||
|
> <property name="icon-size">GTK_ICON_SIZE_LARGE</property>
|
||||||
|
20c21
|
||||||
|
< <property name="xalign">0</property>
|
||||||
|
---
|
||||||
|
> <property name="xalign">0.5</property>
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Each view item has two properties, "gicon" in GtkImage and "label" in GtkLabel.
|
||||||
|
Because GFileInfo doesn't have properties correspond to icon object 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
|
1 GIcon *
|
||||||
|
2 get_icon (GtkListItem *item, GFileInfo *info) {
|
||||||
|
3 GIcon *icon;
|
||||||
|
4
|
||||||
|
5 if (! G_IS_FILE_INFO (info))
|
||||||
|
6 return NULL;
|
||||||
|
7 else {
|
||||||
|
8 icon = g_file_info_get_icon (info);
|
||||||
|
9 g_object_ref (icon);
|
||||||
|
10 return icon;
|
||||||
|
11 }
|
||||||
|
12 }
|
||||||
|
13
|
||||||
|
14 char *
|
||||||
|
15 get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||||
|
16 if (! G_IS_FILE_INFO (info))
|
||||||
|
17 return NULL;
|
||||||
|
18 else
|
||||||
|
19 return g_strdup (g_file_info_get_name (info));
|
||||||
|
20 }
|
||||||
|
~~~
|
||||||
|
|
||||||
|
One important thing is view items own the object 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.
|
||||||
|
|
||||||
|
## An activate signal handler of the action
|
||||||
|
|
||||||
|
An activate signal handler `view_activate` switches the view.
|
||||||
|
It does two things.
|
||||||
|
|
||||||
|
- Change the child widget of GtkScrolledWindow.
|
||||||
|
- Change the CSS of buttons to show the current state.
|
||||||
|
|
||||||
|
~~~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 }
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The second parameter of this handler is the target of the clicked button.
|
||||||
|
Its type is GVariant.
|
||||||
|
|
||||||
|
- If `btnlist` has been clicked, then `parameter` is "list".
|
||||||
|
- If `btngrid` has been clicked, then `parameter` is "grid".
|
||||||
|
|
||||||
|
The third parameter `user_data` points GtkScrolledWindow, which is set in the `g_signal_connect` function.
|
||||||
|
|
||||||
|
- 4: `g_variant_get_string` gets the string from the GVariant variable.
|
||||||
|
- 8-14: Sets the child of `scr`.
|
||||||
|
- 15-17: Sets the CSS of 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.
|
||||||
|
|
||||||
|
## Activate signal of 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.
|
||||||
|
You can do anything you like by connecting the "activate" signal to the handler.
|
||||||
|
|
||||||
|
The example `list4` launches `tfe` text file editor if the item of the list is a text file.
|
||||||
|
|
||||||
|
~~~C
|
||||||
|
static void
|
||||||
|
list_activate (GtkListView *list, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grid_activate (GtkGridView *grid, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_grid_view_get_model (grid)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
... ...
|
||||||
|
... ...
|
||||||
|
|
||||||
|
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_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 list.
|
||||||
|
So you can get the item with `g_list_model_get_item` function.
|
||||||
|
|
||||||
|
## Content type and launching an application
|
||||||
|
|
||||||
|
The function `launch_tfe_with_file` launches `tfe` with the file whose information has been taken by GFileInfo object, if the file is a text file.
|
||||||
|
|
||||||
|
GFileInfo has information about file type.
|
||||||
|
The file type is like "text/plain", "text/x-csrc" and so on.
|
||||||
|
It is called content type.
|
||||||
|
Content type can be got with `g_file_info_get_content_type` function.
|
||||||
|
|
||||||
|
~~~C
|
||||||
|
1 static void
|
||||||
|
2 launch_tfe_with_file (GFileInfo *info) {
|
||||||
|
3 GError *err = NULL;
|
||||||
|
4 GFile *file;
|
||||||
|
5 GList *files = NULL;
|
||||||
|
6 const char *content_type;
|
||||||
|
7 const char *text_type = "text/";
|
||||||
|
8 GAppInfo *appinfo;
|
||||||
|
9 int i;
|
||||||
|
10
|
||||||
|
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 return;
|
||||||
|
25 }
|
||||||
|
26 err = NULL;
|
||||||
|
27 file = g_file_new_for_path (g_file_info_get_name (info));
|
||||||
|
28 files = g_list_append (files, file);
|
||||||
|
29 if (! (g_app_info_launch (appinfo, files, NULL, &err))) {
|
||||||
|
30 g_printerr ("%s\n", err->message);
|
||||||
|
31 }
|
||||||
|
32 g_list_free_full (files, g_object_unref);
|
||||||
|
33 g_object_unref (appinfo);
|
||||||
|
34 }
|
||||||
|
~~~
|
||||||
|
|
||||||
|
- 13: Gets the content type of GFileInfo.
|
||||||
|
- 14: Prints the content type.
|
||||||
|
This is only useful to know a content type of a file.
|
||||||
|
- 17-20: If the content type doesn't begin with "text/", then it returns.
|
||||||
|
- 21: Creates GAppInfo object of `tfe` application.
|
||||||
|
GAppInfo is interface and the variable `appinfo` points a GDesktopAppInfo object.
|
||||||
|
GAppInfo is a collection of information of an application.
|
||||||
|
- 29: 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 object 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 GError.
|
||||||
|
- 32: `g_list_free_full` frees the memories used by the list and items.
|
||||||
|
|
||||||
|
At present, my ubuntu runs on Gtk3, not Gtk4.
|
||||||
|
If it runs on Gtk4, 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.
|
||||||
|
|
||||||
|
## Compilation and execution
|
||||||
|
|
||||||
|
The source files are located in [src/list4](../src/list4) directory.
|
||||||
|
To compile and execute list4, type as follows.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
$ cd list4 # or cd src/list4. It depends your current directory.
|
||||||
|
$ meson _build
|
||||||
|
$ ninja -C _build
|
||||||
|
$ _build/list3
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Then a file list appears as a list style.
|
||||||
|
Click on a button on the tool bar so that you can change the style to grid or back to list.
|
||||||
|
Double click "list4.c" item, then `tfe` text editor runs with the argument "list4.c".
|
||||||
|
The following is the screenshot.
|
||||||
|
|
||||||
|
![Screenshot](../image/screenshot_list4.png)
|
||||||
|
|
||||||
|
## "gbytes" property of GtkBuilderListItemFactory
|
||||||
|
|
||||||
|
GtkBuilderListItemFactory has "gbytes" property.
|
||||||
|
The property contains a byte sequence of ui data.
|
||||||
|
If you use this property, you can put the contents of `factory_list.ui` and `factory_grid.ui`into `list4.ui`.
|
||||||
|
The following shows a part of the new list4.ui file.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
<object class="GtkListView" id="list">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkSingleSelection" id="singleselection">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkDirectoryList" id="directorylist">
|
||||||
|
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
<property name="factory">
|
||||||
|
<object class="GtkBuilderListItemFactory">
|
||||||
|
<property name="bytes"><![CDATA[
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="GtkListItem">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<binding name="gicon">
|
||||||
|
<closure type="GIcon" function="get_icon">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<binding name="label">
|
||||||
|
<closure type="gchararray" function="get_file_name">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
|
]]></property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
~~~
|
||||||
|
|
||||||
|
CDATA section begins with "<![CDATA[" and ends with "]]>".
|
||||||
|
The contents of CDATA section is recognized as a string.
|
||||||
|
Any character, even if it is a key syntax marker such as '<' or '>', is recognized literally.
|
||||||
|
Therefore, the text between "<![CDATA[" and "]]>" is inserted to "bytes" property as it is.
|
||||||
|
|
||||||
|
This method decreases the number of ui files.
|
||||||
|
But, the new ui file is a bit complicated especially for the beginners.
|
||||||
|
If you feel some difficulty, it is better for you to separate the ui file.
|
||||||
|
|
||||||
|
A directory [src/list5](../src/list5) includes the ui file above.
|
||||||
|
|
||||||
|
|
||||||
|
Up: [Readme.md](../Readme.md), Prev: [Section 24](sec24.md)
|
BIN
image/directorylist.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
image/directorylist.xcf
Normal file
BIN
image/list4.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
image/screenshot_list4.png
Normal file
After Width: | Height: | Size: 173 KiB |
33
src/list4/factory_grid.ui
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="GtkListItem">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-size">GTK_ICON_SIZE_LARGE</property>
|
||||||
|
<binding name="gicon">
|
||||||
|
<closure type="GIcon" function="get_icon">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<binding name="label">
|
||||||
|
<closure type="gchararray" function="get_file_name">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
|
|
32
src/list4/factory_list.ui
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="GtkListItem">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<binding name="gicon">
|
||||||
|
<closure type="GIcon" function="get_icon">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<binding name="label">
|
||||||
|
<closure type="gchararray" function="get_file_name">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
|
|
BIN
src/list4/grid.png
Normal file
After Width: | Height: | Size: 628 B |
BIN
src/list4/list.png
Normal file
After Width: | Height: | Size: 611 B |
171
src/list4/list4.c
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static GtkWidget *list;
|
||||||
|
static GtkWidget *grid;
|
||||||
|
static GdkDisplay *display;
|
||||||
|
static GtkCssProvider *provider;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
before_close (GtkWindow *win, gpointer user_data) {
|
||||||
|
g_object_unref (list);
|
||||||
|
g_object_unref (grid);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
view_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||||
|
GtkScrolledWindow *scr = GTK_SCROLLED_WINDOW (user_data);
|
||||||
|
const char *view = g_variant_get_string (parameter, NULL);
|
||||||
|
const char *other;
|
||||||
|
char *css;
|
||||||
|
|
||||||
|
if (strcmp (view, "list") == 0) {
|
||||||
|
other = "grid";
|
||||||
|
gtk_scrolled_window_set_child (scr, list);
|
||||||
|
}else {
|
||||||
|
other = "list";
|
||||||
|
gtk_scrolled_window_set_child (scr, grid);
|
||||||
|
}
|
||||||
|
css = g_strdup_printf ("button#btn%s {background: silver;} button#btn%s {background: white;}", view, other);
|
||||||
|
gtk_css_provider_load_from_data (provider, css, -1);
|
||||||
|
g_free (css);
|
||||||
|
g_action_change_state (G_ACTION (action), parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
launch_tfe_with_file (GFileInfo *info) {
|
||||||
|
GError *err = NULL;
|
||||||
|
GFile *file;
|
||||||
|
GList *files = NULL;
|
||||||
|
const char *content_type;
|
||||||
|
const char *text_type = "text/";
|
||||||
|
GAppInfo *appinfo;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (! info)
|
||||||
|
return;
|
||||||
|
content_type = g_file_info_get_content_type (info);
|
||||||
|
g_print ("%s\n", content_type); /* This line can be commented out if unnecessary */
|
||||||
|
if (! content_type)
|
||||||
|
return;
|
||||||
|
for (i=0;i<5;++i) {
|
||||||
|
if (content_type[i] != text_type[i])
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appinfo = g_app_info_create_from_commandline ("tfe", "tfe", G_APP_INFO_CREATE_NONE, &err);
|
||||||
|
if (err) {
|
||||||
|
g_printerr ("%s\n", err->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
err = NULL;
|
||||||
|
file = g_file_new_for_path (g_file_info_get_name (info));
|
||||||
|
files = g_list_append (files, file);
|
||||||
|
if (! (g_app_info_launch (appinfo, files, NULL, &err))) {
|
||||||
|
g_printerr ("%s\n", err->message);
|
||||||
|
}
|
||||||
|
g_list_free_full (files, g_object_unref);
|
||||||
|
g_object_unref (appinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_activate (GtkListView *list, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grid_activate (GtkGridView *grid, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_grid_view_get_model (grid)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
GIcon *
|
||||||
|
get_icon (GtkListItem *item, GFileInfo *info) {
|
||||||
|
GIcon *icon;
|
||||||
|
|
||||||
|
if (! G_IS_FILE_INFO (info))
|
||||||
|
return NULL;
|
||||||
|
else {
|
||||||
|
icon = g_file_info_get_icon (info);
|
||||||
|
g_object_ref (icon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||||
|
if (! G_IS_FILE_INFO (info))
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return g_strdup (g_file_info_get_name (info));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- activate, open, startup handlers ----- */
|
||||||
|
static void
|
||||||
|
app_activate (GApplication *application) {
|
||||||
|
GtkApplication *app = GTK_APPLICATION (application);
|
||||||
|
GFile *file;
|
||||||
|
GSimpleAction *act_view;
|
||||||
|
|
||||||
|
GtkBuilder *build = gtk_builder_new_from_resource ("/com/github/ToshioCP/list4/list4.ui");
|
||||||
|
GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||||
|
GtkWidget *scr = GTK_WIDGET (gtk_builder_get_object (build, "scr"));
|
||||||
|
list = GTK_WIDGET (gtk_builder_get_object (build, "list"));
|
||||||
|
grid = GTK_WIDGET (gtk_builder_get_object (build, "grid"));
|
||||||
|
GtkDirectoryList *directorylist = GTK_DIRECTORY_LIST (gtk_builder_get_object (build, "directorylist"));
|
||||||
|
g_object_ref (list);
|
||||||
|
g_object_ref (grid);
|
||||||
|
g_object_unref (build);
|
||||||
|
|
||||||
|
GtkListItemFactory *factory_list = gtk_builder_list_item_factory_new_from_resource (NULL, "/com/github/ToshioCP/list4/factory_list.ui");
|
||||||
|
GtkListItemFactory *factory_grid = gtk_builder_list_item_factory_new_from_resource (NULL, "/com/github/ToshioCP/list4/factory_grid.ui");
|
||||||
|
|
||||||
|
gtk_window_set_application (GTK_WINDOW (win), app);
|
||||||
|
/* First, 'list' is a child of scr. The child will be list or grid according to the clicked button, btnlist or btngrid. */
|
||||||
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), list);
|
||||||
|
|
||||||
|
file = g_file_new_for_path (".");
|
||||||
|
gtk_directory_list_set_file (directorylist, file);
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
|
gtk_list_view_set_factory (GTK_LIST_VIEW (list), factory_list);
|
||||||
|
gtk_grid_view_set_factory (GTK_GRID_VIEW (grid), factory_grid);
|
||||||
|
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL);
|
||||||
|
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
|
||||||
|
|
||||||
|
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);
|
||||||
|
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
|
||||||
|
|
||||||
|
display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_data (provider, "button#btnlist {background: silver;} button#btngrid {background: white;}", -1);
|
||||||
|
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
|
||||||
|
g_signal_connect (GTK_WINDOW (win), "close-request", G_CALLBACK (before_close), NULL);
|
||||||
|
gtk_widget_show (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
app_startup (GApplication *application) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define APPLICATION_ID "com.github.ToshioCP.list4"
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv) {
|
||||||
|
GtkApplication *app;
|
||||||
|
int stat;
|
||||||
|
|
||||||
|
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||||
|
|
||||||
|
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
|
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
|
/* g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);*/
|
||||||
|
|
||||||
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
|
g_object_unref (app);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
10
src/list4/list4.gresource.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/com/github/ToshioCP/list4">
|
||||||
|
<file>list4.ui</file>
|
||||||
|
<file>factory_list.ui</file>
|
||||||
|
<file>factory_grid.ui</file>
|
||||||
|
<file>list.png</file>
|
||||||
|
<file>grid.png</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
73
src/list4/list4.ui
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<object class="GtkApplicationWindow" id="win">
|
||||||
|
<property name="title">file list</property>
|
||||||
|
<property name="default-width">600</property>
|
||||||
|
<property name="default-height">400</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="boxv">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="boxh">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="dmy1">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnlist">
|
||||||
|
<property name="name">btnlist</property>
|
||||||
|
<property name="action-name">win.view</property>
|
||||||
|
<property name="action-target">'list'</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="resource">/com/github/ToshioCP/list4/list.png</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btngrid">
|
||||||
|
<property name="name">btngrid</property>
|
||||||
|
<property name="action-name">win.view</property>
|
||||||
|
<property name="action-target">'grid'</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="resource">/com/github/ToshioCP/list4/grid.png</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="dmy2">
|
||||||
|
<property name="width-chars">10</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scr">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="vexpand">TRUE</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListView" id="list">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkSingleSelection" id="singleselection">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkDirectoryList" id="directorylist">
|
||||||
|
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkGridView" id="grid">
|
||||||
|
<property name="model">singleselection</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
||||||
|
|
11
src/list4/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
project('list4', 'c')
|
||||||
|
|
||||||
|
gtkdep = dependency('gtk4')
|
||||||
|
|
||||||
|
gnome=import('gnome')
|
||||||
|
resources = gnome.compile_resources('resources','list4.gresource.xml')
|
||||||
|
|
||||||
|
sourcefiles=files('list4.c')
|
||||||
|
|
||||||
|
executable('list4', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||||
|
|
BIN
src/list5/grid.png
Normal file
After Width: | Height: | Size: 628 B |
BIN
src/list5/list.png
Normal file
After Width: | Height: | Size: 611 B |
166
src/list5/list5.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static GtkWidget *list;
|
||||||
|
static GtkWidget *grid;
|
||||||
|
static GdkDisplay *display;
|
||||||
|
static GtkCssProvider *provider;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
before_close (GtkWindow *win, gpointer user_data) {
|
||||||
|
g_object_unref (list);
|
||||||
|
g_object_unref (grid);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
view_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||||
|
GtkScrolledWindow *scr = GTK_SCROLLED_WINDOW (user_data);
|
||||||
|
const char *view = g_variant_get_string (parameter, NULL);
|
||||||
|
const char *other;
|
||||||
|
char *css;
|
||||||
|
|
||||||
|
if (strcmp (view, "list") == 0) {
|
||||||
|
other = "grid";
|
||||||
|
gtk_scrolled_window_set_child (scr, list);
|
||||||
|
}else {
|
||||||
|
other = "list";
|
||||||
|
gtk_scrolled_window_set_child (scr, grid);
|
||||||
|
}
|
||||||
|
css = g_strdup_printf ("button#btn%s {background: silver;} button#btn%s {background: white;}", view, other);
|
||||||
|
gtk_css_provider_load_from_data (provider, css, -1);
|
||||||
|
g_free (css);
|
||||||
|
g_action_change_state (G_ACTION (action), parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
launch_tfe_with_file (GFileInfo *info) {
|
||||||
|
GError *err = NULL;
|
||||||
|
GFile *file;
|
||||||
|
GList *files = NULL;
|
||||||
|
const char *content_type;
|
||||||
|
const char *text_type = "text/";
|
||||||
|
GAppInfo *appinfo;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (! info)
|
||||||
|
return;
|
||||||
|
content_type = g_file_info_get_content_type (info);
|
||||||
|
g_print ("%s\n", content_type); /* This line can be commented out if unnecessary */
|
||||||
|
if (! content_type)
|
||||||
|
return;
|
||||||
|
for (i=0;i<5;++i) {
|
||||||
|
if (content_type[i] != text_type[i])
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appinfo = g_app_info_create_from_commandline ("tfe", "tfe", G_APP_INFO_CREATE_NONE, &err);
|
||||||
|
if (err) {
|
||||||
|
g_printerr ("%s\n", err->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
err = NULL;
|
||||||
|
file = g_file_new_for_path (g_file_info_get_name (info));
|
||||||
|
files = g_list_append (files, file);
|
||||||
|
if (! (g_app_info_launch (appinfo, files, NULL, &err))) {
|
||||||
|
g_printerr ("%s\n", err->message);
|
||||||
|
}
|
||||||
|
g_list_free_full (files, g_object_unref);
|
||||||
|
g_object_unref (appinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_activate (GtkListView *list, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grid_activate (GtkGridView *grid, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_grid_view_get_model (grid)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
GIcon *
|
||||||
|
get_icon (GtkListItem *item, GFileInfo *info) {
|
||||||
|
GIcon *icon;
|
||||||
|
|
||||||
|
if (! G_IS_FILE_INFO (info))
|
||||||
|
return NULL;
|
||||||
|
else {
|
||||||
|
icon = g_file_info_get_icon (info);
|
||||||
|
g_object_ref (icon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||||
|
if (! G_IS_FILE_INFO (info))
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return g_strdup (g_file_info_get_name (info));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- activate, open, startup handlers ----- */
|
||||||
|
static void
|
||||||
|
app_activate (GApplication *application) {
|
||||||
|
GtkApplication *app = GTK_APPLICATION (application);
|
||||||
|
GFile *file;
|
||||||
|
GSimpleAction *act_view;
|
||||||
|
|
||||||
|
GtkBuilder *build = gtk_builder_new_from_resource ("/com/github/ToshioCP/list5/list5.ui");
|
||||||
|
GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||||
|
GtkWidget *scr = GTK_WIDGET (gtk_builder_get_object (build, "scr"));
|
||||||
|
list = GTK_WIDGET (gtk_builder_get_object (build, "list"));
|
||||||
|
grid = GTK_WIDGET (gtk_builder_get_object (build, "grid"));
|
||||||
|
GtkDirectoryList *directorylist = GTK_DIRECTORY_LIST (gtk_builder_get_object (build, "directorylist"));
|
||||||
|
g_object_ref (list);
|
||||||
|
g_object_ref (grid);
|
||||||
|
g_object_unref (build);
|
||||||
|
|
||||||
|
gtk_window_set_application (GTK_WINDOW (win), app);
|
||||||
|
/* First, 'list' is a child of scr. The child will be list or grid according to the clicked button, btnlist or btngrid. */
|
||||||
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), list);
|
||||||
|
|
||||||
|
file = g_file_new_for_path (".");
|
||||||
|
gtk_directory_list_set_file (directorylist, file);
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
|
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL);
|
||||||
|
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
|
||||||
|
|
||||||
|
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);
|
||||||
|
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
|
||||||
|
|
||||||
|
display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_data (provider, "button#btnlist {background: silver;} button#btngrid {background: white;}", -1);
|
||||||
|
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
|
||||||
|
g_signal_connect (GTK_WINDOW (win), "close-request", G_CALLBACK (before_close), NULL);
|
||||||
|
gtk_widget_show (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
app_startup (GApplication *application) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define APPLICATION_ID "com.github.ToshioCP.list5"
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv) {
|
||||||
|
GtkApplication *app;
|
||||||
|
int stat;
|
||||||
|
|
||||||
|
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||||
|
|
||||||
|
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
|
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
|
/* g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);*/
|
||||||
|
|
||||||
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
|
g_object_unref (app);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
8
src/list5/list5.gresource.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/com/github/ToshioCP/list5">
|
||||||
|
<file>list5.ui</file>
|
||||||
|
<file>list.png</file>
|
||||||
|
<file>grid.png</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
148
src/list5/list5.ui
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<object class="GtkApplicationWindow" id="win">
|
||||||
|
<property name="title">file list</property>
|
||||||
|
<property name="default-width">600</property>
|
||||||
|
<property name="default-height">400</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="boxv">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="boxh">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="dmy1">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnlist">
|
||||||
|
<property name="name">btnlist</property>
|
||||||
|
<property name="action-name">win.view</property>
|
||||||
|
<property name="action-target">'list'</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="resource">/com/github/ToshioCP/list4/list.png</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btngrid">
|
||||||
|
<property name="name">btngrid</property>
|
||||||
|
<property name="action-name">win.view</property>
|
||||||
|
<property name="action-target">'grid'</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="resource">/com/github/ToshioCP/list4/grid.png</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="dmy2">
|
||||||
|
<property name="width-chars">10</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scr">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="vexpand">TRUE</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListView" id="list">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkSingleSelection" id="singleselection">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkDirectoryList" id="directorylist">
|
||||||
|
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
<property name="factory">
|
||||||
|
<object class="GtkBuilderListItemFactory">
|
||||||
|
<property name="bytes"><![CDATA[
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="GtkListItem">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<binding name="gicon">
|
||||||
|
<closure type="GIcon" function="get_icon">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<binding name="label">
|
||||||
|
<closure type="gchararray" function="get_file_name">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
|
]]></property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkGridView" id="grid">
|
||||||
|
<property name="model">singleselection</property>
|
||||||
|
<property name="factory">
|
||||||
|
<object class="GtkBuilderListItemFactory">
|
||||||
|
<property name="bytes"><![CDATA[
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="GtkListItem">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-size">GTK_ICON_SIZE_LARGE</property>
|
||||||
|
<binding name="gicon">
|
||||||
|
<closure type="GIcon" function="get_icon">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<binding name="label">
|
||||||
|
<closure type="gchararray" function="get_file_name">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
|
]]></property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
||||||
|
|
11
src/list5/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
project('list5', 'c')
|
||||||
|
|
||||||
|
gtkdep = dependency('gtk4')
|
||||||
|
|
||||||
|
gnome=import('gnome')
|
||||||
|
resources = gnome.compile_resources('resources','list5.gresource.xml')
|
||||||
|
|
||||||
|
sourcefiles=files('list5.c')
|
||||||
|
|
||||||
|
executable('list5', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||||
|
|
|
@ -30,7 +30,7 @@ teardown_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_d
|
||||||
|
|
||||||
/* ----- activate, open, startup handlers ----- */
|
/* ----- activate, open, startup handlers ----- */
|
||||||
static void
|
static void
|
||||||
tfe_activate (GApplication *application) {
|
app_activate (GApplication *application) {
|
||||||
GtkApplication *app = GTK_APPLICATION (application);
|
GtkApplication *app = GTK_APPLICATION (application);
|
||||||
GtkWidget *win = gtk_application_window_new (app);
|
GtkWidget *win = gtk_application_window_new (app);
|
||||||
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||||
|
@ -55,7 +55,7 @@ tfe_activate (GApplication *application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tfe_startup (GApplication *application) {
|
app_startup (GApplication *application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- main ----- */
|
/* ----- main ----- */
|
||||||
|
@ -66,8 +66,8 @@ main (int argc, char **argv) {
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.list1", G_APPLICATION_FLAGS_NONE);
|
app = gtk_application_new ("com.github.ToshioCP.list1", G_APPLICATION_FLAGS_NONE);
|
||||||
|
|
||||||
g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
|
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
/* ----- activate, open, startup handlers ----- */
|
/* ----- activate, open, startup handlers ----- */
|
||||||
static void
|
static void
|
||||||
tfe_activate (GApplication *application) {
|
app_activate (GApplication *application) {
|
||||||
GtkApplication *app = GTK_APPLICATION (application);
|
GtkApplication *app = GTK_APPLICATION (application);
|
||||||
GtkWidget *win = gtk_application_window_new (app);
|
GtkWidget *win = gtk_application_window_new (app);
|
||||||
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||||
|
@ -39,7 +39,7 @@ tfe_activate (GApplication *application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tfe_startup (GApplication *application) {
|
app_startup (GApplication *application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- main ----- */
|
/* ----- main ----- */
|
||||||
|
@ -50,8 +50,8 @@ main (int argc, char **argv) {
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.list2", G_APPLICATION_FLAGS_NONE);
|
app = gtk_application_new ("com.github.ToshioCP.list2", G_APPLICATION_FLAGS_NONE);
|
||||||
|
|
||||||
g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
|
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
|
|
|
@ -10,7 +10,7 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||||
|
|
||||||
/* ----- activate, open, startup handlers ----- */
|
/* ----- activate, open, startup handlers ----- */
|
||||||
static void
|
static void
|
||||||
tfe_activate (GApplication *application) {
|
app_activate (GApplication *application) {
|
||||||
GtkApplication *app = GTK_APPLICATION (application);
|
GtkApplication *app = GTK_APPLICATION (application);
|
||||||
GtkWidget *win = gtk_application_window_new (app);
|
GtkWidget *win = gtk_application_window_new (app);
|
||||||
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||||
|
@ -41,13 +41,12 @@ tfe_activate (GApplication *application) {
|
||||||
GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
|
GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
|
||||||
|
|
||||||
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
||||||
gtk_list_view_set_enable_rubberband (GTK_LIST_VIEW (lv), TRUE);
|
|
||||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||||
gtk_widget_show (win);
|
gtk_widget_show (win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tfe_startup (GApplication *application) {
|
app_startup (GApplication *application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- main ----- */
|
/* ----- main ----- */
|
||||||
|
@ -56,10 +55,10 @@ main (int argc, char **argv) {
|
||||||
GtkApplication *app;
|
GtkApplication *app;
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
app = gtk_application_new ("com.github.ToshioCP.list2", G_APPLICATION_FLAGS_NONE);
|
app = gtk_application_new ("com.github.ToshioCP.list3", G_APPLICATION_FLAGS_NONE);
|
||||||
|
|
||||||
g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||||
g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||||
|
|
||||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
g_object_unref (app);
|
g_object_unref (app);
|
||||||
|
|
|
@ -303,5 +303,5 @@ $ comp list3
|
||||||
$ ./a.out
|
$ ./a.out
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
![screenshot list3](../image/list3.png){width=6.04cm height=4.41cm}
|
![screenshot list3](../image/list3.png){width=10cm height=7.3cm}
|
||||||
|
|
||||||
|
|
345
src/sec25.src.md
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
# GtkGridView and activate signal
|
||||||
|
|
||||||
|
GtkGridView is similar to GtkListView.
|
||||||
|
It displays a GListModel as a grid, which is like a square tessellation.
|
||||||
|
|
||||||
|
![Grid](../image/list4.png){width=10cm height=6.6cm}
|
||||||
|
|
||||||
|
This is often seen when you use a file browser like nautilus.
|
||||||
|
|
||||||
|
In this section, let's make a very simple file browser `list4`.
|
||||||
|
It just shows the files in the current directory.
|
||||||
|
And a user can choose list or grid by clicking on buttons in the tool bar.
|
||||||
|
Each item in the list or grid has an icon and a filename.
|
||||||
|
In addition, `list4` provides the way to open the `tfe` text editor to show a text file.
|
||||||
|
A user can do that by double clicking on an item or pressing enter key when an item is selected.
|
||||||
|
|
||||||
|
## GtkDirectoryList
|
||||||
|
|
||||||
|
GtkDirectoryList implements GListModel and it contains information of files in a certain directory.
|
||||||
|
The items of the list are GFileInfo objects.
|
||||||
|
|
||||||
|
In the `list4` source files, GtkDirectoryList is described in a ui file and built by GtkBuilder.
|
||||||
|
It is referenced to by a GtkSingleSelection model and the GtkSingleSelection model is referenced to by a GListView or GGridView object.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
GtkListView (model property) => GtkSingleSelection (model property) => GtkDirectoryList
|
||||||
|
GtkGridView (model property) => GtkSingleSelection (model property) => GtkDirectoryList
|
||||||
|
~~~
|
||||||
|
|
||||||
|
![DirectoryList](../image/directorylist.png){width=10cm height=7.5cm}
|
||||||
|
|
||||||
|
The part of the ui file `list4.ui` is as follows.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
<object class="GtkListView" id="list">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkSingleSelection" id="singleselection">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkDirectoryList" id="directorylist">
|
||||||
|
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkGridView" id="grid">
|
||||||
|
<property name="model">singleselection</property>
|
||||||
|
</object>
|
||||||
|
~~~
|
||||||
|
|
||||||
|
GtkDirectoryList has an "attributes" property.
|
||||||
|
It is attributes of GFileInfo such as "standard::name", "standard::icon" and "standard::content-type".
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
@@@include
|
||||||
|
list4/list4.ui
|
||||||
|
@@@
|
||||||
|
|
||||||
|
The file consists of two parts.
|
||||||
|
The first part begins at the third line and ends at the 57th line.
|
||||||
|
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.
|
||||||
|
This is 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`.
|
||||||
|
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.
|
||||||
|
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 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.
|
||||||
|
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.
|
||||||
|
The action name is "win.view" and the target is "list".
|
||||||
|
Generally, a target is GVariant, which can be string, integer, float and so on.
|
||||||
|
You need to use GVariant text format to write GVariant value in ui files.
|
||||||
|
If the type of the GVarinat value is string, then the value with GVariant text format is bounded by single quotes or double quotes.
|
||||||
|
Because ui file is xml format text, single quote cannot be written without escape.
|
||||||
|
Its escape sequence is \'.
|
||||||
|
Therefore, the target 'list' is written as \'list\'.
|
||||||
|
Because the button is connected to the action, "clicked" signal handler isn't needed.
|
||||||
|
- 23-27: The child widget of the button is GtkImage.
|
||||||
|
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.
|
||||||
|
|
||||||
|
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));
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The signal handler `view_activated` will be explained later.
|
||||||
|
|
||||||
|
## Factories
|
||||||
|
|
||||||
|
Each view (GtkListView and GtkGridView) has its own factory because its items have different structure of widgets.
|
||||||
|
The factories are GtkBuilderListItemFactory objects.
|
||||||
|
Their ui files are as follows.
|
||||||
|
|
||||||
|
factory_list.ui
|
||||||
|
|
||||||
|
@@@include
|
||||||
|
list4/factory_list.ui
|
||||||
|
@@@
|
||||||
|
|
||||||
|
factory_grid.ui
|
||||||
|
|
||||||
|
@@@include
|
||||||
|
list4/factory_grid.ui
|
||||||
|
@@@
|
||||||
|
|
||||||
|
The two files above are almost same.
|
||||||
|
The difference is:
|
||||||
|
|
||||||
|
- The orientation of the box
|
||||||
|
- The icon size
|
||||||
|
- The position of the text of the label
|
||||||
|
|
||||||
|
@@@shell
|
||||||
|
cd list4; diff factory_list.ui factory_grid.ui
|
||||||
|
@@@
|
||||||
|
|
||||||
|
Each view item has two properties, "gicon" in GtkImage and "label" in GtkLabel.
|
||||||
|
Because GFileInfo doesn't have properties correspond to icon object 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.
|
||||||
|
|
||||||
|
@@@include
|
||||||
|
list4/list4.c get_icon get_file_name
|
||||||
|
@@@
|
||||||
|
|
||||||
|
One important thing is view items own the object 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.
|
||||||
|
|
||||||
|
## An activate signal handler of the action
|
||||||
|
|
||||||
|
An activate signal handler `view_activate` switches the view.
|
||||||
|
It does two things.
|
||||||
|
|
||||||
|
- Change the child widget of GtkScrolledWindow.
|
||||||
|
- Change the CSS of buttons to show the current state.
|
||||||
|
|
||||||
|
@@@include
|
||||||
|
list4/list4.c view_activated
|
||||||
|
@@@
|
||||||
|
|
||||||
|
The second parameter of this handler is the target of the clicked button.
|
||||||
|
Its type is GVariant.
|
||||||
|
|
||||||
|
- If `btnlist` has been clicked, then `parameter` is "list".
|
||||||
|
- If `btngrid` has been clicked, then `parameter` is "grid".
|
||||||
|
|
||||||
|
The third parameter `user_data` points GtkScrolledWindow, which is set in the `g_signal_connect` function.
|
||||||
|
|
||||||
|
- 4: `g_variant_get_string` gets the string from the GVariant variable.
|
||||||
|
- 8-14: Sets the child of `scr`.
|
||||||
|
- 15-17: Sets the CSS of 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.
|
||||||
|
|
||||||
|
## Activate signal of 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.
|
||||||
|
You can do anything you like by connecting the "activate" signal to the handler.
|
||||||
|
|
||||||
|
The example `list4` launches `tfe` text file editor if the item of the list is a text file.
|
||||||
|
|
||||||
|
~~~C
|
||||||
|
static void
|
||||||
|
list_activate (GtkListView *list, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grid_activate (GtkGridView *grid, int position, gpointer user_data) {
|
||||||
|
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_grid_view_get_model (grid)), position));
|
||||||
|
launch_tfe_with_file (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
... ...
|
||||||
|
... ...
|
||||||
|
|
||||||
|
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_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 list.
|
||||||
|
So you can get the item with `g_list_model_get_item` function.
|
||||||
|
|
||||||
|
## Content type and launching an application
|
||||||
|
|
||||||
|
The function `launch_tfe_with_file` launches `tfe` with the file whose information has been taken by GFileInfo object, if the file is a text file.
|
||||||
|
|
||||||
|
GFileInfo has information about file type.
|
||||||
|
The file type is like "text/plain", "text/x-csrc" and so on.
|
||||||
|
It is called content type.
|
||||||
|
Content type can be got with `g_file_info_get_content_type` function.
|
||||||
|
|
||||||
|
@@@include
|
||||||
|
list4/list4.c launch_tfe_with_file
|
||||||
|
@@@
|
||||||
|
|
||||||
|
- 13: Gets the content type of GFileInfo.
|
||||||
|
- 14: Prints the content type.
|
||||||
|
This is only useful to know a content type of a file.
|
||||||
|
- 17-20: If the content type doesn't begin with "text/", then it returns.
|
||||||
|
- 21: Creates GAppInfo object of `tfe` application.
|
||||||
|
GAppInfo is interface and the variable `appinfo` points a GDesktopAppInfo object.
|
||||||
|
GAppInfo is a collection of information of an application.
|
||||||
|
- 29: 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 object 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 GError.
|
||||||
|
- 32: `g_list_free_full` frees the memories used by the list and items.
|
||||||
|
|
||||||
|
At present, my ubuntu runs on Gtk3, not Gtk4.
|
||||||
|
If it runs on Gtk4, 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.
|
||||||
|
|
||||||
|
## Compilation and execution
|
||||||
|
|
||||||
|
The source files are located in [src/list4](list4) directory.
|
||||||
|
To compile and execute list4, type as follows.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
$ cd list4 # or cd src/list4. It depends your current directory.
|
||||||
|
$ meson _build
|
||||||
|
$ ninja -C _build
|
||||||
|
$ _build/list3
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Then a file list appears as a list style.
|
||||||
|
Click on a button on the tool bar so that you can change the style to grid or back to list.
|
||||||
|
Double click "list4.c" item, then `tfe` text editor runs with the argument "list4.c".
|
||||||
|
The following is the screenshot.
|
||||||
|
|
||||||
|
![Screenshot](../image/screenshot_list4.png){width=8cm height=5.62cm}
|
||||||
|
|
||||||
|
## "gbytes" property of GtkBuilderListItemFactory
|
||||||
|
|
||||||
|
GtkBuilderListItemFactory has "gbytes" property.
|
||||||
|
The property contains a byte sequence of ui data.
|
||||||
|
If you use this property, you can put the contents of `factory_list.ui` and `factory_grid.ui`into `list4.ui`.
|
||||||
|
The following shows a part of the new list4.ui file.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
|
<object class="GtkListView" id="list">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkSingleSelection" id="singleselection">
|
||||||
|
<property name="model">
|
||||||
|
<object class="GtkDirectoryList" id="directorylist">
|
||||||
|
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
<property name="factory">
|
||||||
|
<object class="GtkBuilderListItemFactory">
|
||||||
|
<property name="bytes"><![CDATA[
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="GtkListItem">
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<binding name="gicon">
|
||||||
|
<closure type="GIcon" function="get_icon">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="hexpand">TRUE</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<binding name="label">
|
||||||
|
<closure type="gchararray" function="get_file_name">
|
||||||
|
<lookup name="item">GtkListItem</lookup>
|
||||||
|
</closure>
|
||||||
|
</binding>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
|
]]></property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
~~~
|
||||||
|
|
||||||
|
CDATA section begins with "<![CDATA[" and ends with "]]>".
|
||||||
|
The contents of CDATA section is recognized as a string.
|
||||||
|
Any character, even if it is a key syntax marker such as '<' or '>', is recognized literally.
|
||||||
|
Therefore, the text between "<![CDATA[" and "]]>" is inserted to "bytes" property as it is.
|
||||||
|
|
||||||
|
This method decreases the number of ui files.
|
||||||
|
But, the new ui file is a bit complicated especially for the beginners.
|
||||||
|
If you feel some difficulty, it is better for you to separate the ui file.
|
||||||
|
|
||||||
|
A directory [src/list5](list5) includes the ui file above.
|
||||||
|
|