Use fenced code block.

This commit is contained in:
Toshio Sekiya 2021-01-25 18:35:49 +09:00
parent 26fc01e64e
commit 880dd92c82
31 changed files with 3448 additions and 3100 deletions

1
.gitignore vendored
View file

@ -16,6 +16,7 @@ src/tfe5/_build
src/tfe5/hello.txt src/tfe5/hello.txt
src/menu/a.out src/menu/a.out
src/color/_build src/color/_build
src/turtle
html/* html/*
latex/* latex/*

101
Rakefile
View file

@ -156,12 +156,105 @@ EOS
main.gsub!(/@@@ abstract\n/, abstract_latex) main.gsub!(/@@@ abstract\n/, abstract_latex)
helper = <<'EOS' helper = <<'EOS'
\usepackage[pdftex]{graphicx}
\usepackage[colorlinks=true,linkcolor=black]{hyperref}
\usepackage[margin=2.4cm]{geometry}
\usepackage{tikz} \usepackage{tikz}
\usepackage[margin=2.4cm]{geometry}
% -------------------------------------------------------------
% Following codes are extracted from the preamble generated by:
% $ pandoc -s -o sample.tex sample.md
% -------------------------------------------------------------
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
\usepackage{ifxetex,ifluatex}
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\makeatletter
\@ifundefined{KOMAClassName}{% if non-KOMA class
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}}
}{% if KOMA class
\KOMAoptions{parskip=half}}
\makeatother
\usepackage{xcolor}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
\hypersetup{
hidelinks,
pdfcreator={LaTeX via pandoc}}
\urlstyle{same} % disable monospaced font for URLs
\usepackage{color}
\usepackage{fancyvrb}
\newcommand{\VerbBar}{|}
\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
% Add ',fontsize=\small' for more characters per line
\newenvironment{Shaded}{}{}
\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{#1}}
\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
\newcommand{\BuiltInTok}[1]{#1}
\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{#1}}}
\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}}
\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{#1}}
\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{#1}}}
\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
\newcommand{\ExtensionTok}[1]{#1}
\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{#1}}
\newcommand{\ImportTok}[1]{#1}
\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
\newcommand{\NormalTok}[1]{#1}
\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{#1}}
\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{#1}}
\newcommand{\RegionMarkerTok}[1]{#1}
\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}}
\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}}
\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{% \providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
\author{}
\date{}
EOS EOS
# tasks # tasks
@ -262,7 +355,7 @@ end
0.upto(srcfiles.size - 1) do |i| 0.upto(srcfiles.size - 1) do |i|
file "latex/#{srcfiles[i].to_tex}" => (srcfiles[i].c_files << srcfiles[i].path) do file "latex/#{srcfiles[i].to_tex}" => (srcfiles[i].c_files << srcfiles[i].path) do
src2md srcfiles[i].path, "latex/#{srcfiles[i].to_md}", 80 src2md srcfiles[i].path, "latex/#{srcfiles[i].to_md}", 86
sh "pandoc -o latex/#{srcfiles[i].to_tex} --top-level-division=chapter latex/#{srcfiles[i].to_md}" sh "pandoc -o latex/#{srcfiles[i].to_tex} --top-level-division=chapter latex/#{srcfiles[i].to_md}"
File.delete("latex/#{srcfiles[i].to_md}") File.delete("latex/#{srcfiles[i].to_md}")
end end

View file

@ -20,7 +20,7 @@ You can read it without download.
1. [Widgets (2)](gfm/sec5.md) 1. [Widgets (2)](gfm/sec5.md)
1. [Widgets (3)](gfm/sec6.md) 1. [Widgets (3)](gfm/sec6.md)
1. [Define Child object](gfm/sec7.md) 1. [Define Child object](gfm/sec7.md)
1. [Ui file and GtkBuiler](gfm/sec8.md) 1. [Ui file and GtkBuilder](gfm/sec8.md)
1. [Build system](gfm/sec9.md) 1. [Build system](gfm/sec9.md)
1. [Instance and class](gfm/sec10.md) 1. [Instance and class](gfm/sec10.md)
1. [Signals](gfm/sec11.md) 1. [Signals](gfm/sec11.md)

View file

@ -95,10 +95,12 @@ The structure of `TfeTextView` is like the following diagram.
The function `tfe_text_view_new` generates a new TfeTextView instance. The function `tfe_text_view_new` generates a new TfeTextView instance.
1 GtkWidget * ~~~C
2 tfe_text_view_new (void) { 1 GtkWidget *
3 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL)); 2 tfe_text_view_new (void) {
4 } 3 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
4 }
~~~
When this function is run, the following procedure is gone through. When this function is run, the following procedure is gone through.
@ -113,14 +115,16 @@ Step four is done by the function `tfe_text_view_init`.
> In the same way, `gtk_text_view_init`, `gtk_widget_init` and `g_object_init` is the initialization functions of GtkTextView, GtkWidget and GObject respectively. > In the same way, `gtk_text_view_init`, `gtk_widget_init` and `g_object_init` is the initialization functions of GtkTextView, GtkWidget and GObject respectively.
> You can find them in the GTK or GLib source files. > You can find them in the GTK or GLib source files.
1 static void ~~~C
2 tfe_text_view_init (TfeTextView *tv) { 1 static void
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 2 tfe_text_view_init (TfeTextView *tv) {
4 3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
5 tv->file = NULL; 4
6 gtk_text_buffer_set_modified (tb, FALSE); 5 tv->file = NULL;
7 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 6 gtk_text_buffer_set_modified (tb, FALSE);
8 } 7 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
8 }
~~~
`tfe_text_view_init` initializes the instance. `tfe_text_view_init` initializes the instance.
@ -151,44 +155,46 @@ Class comprises mainly pointers to functions.
Those functions are used by the object itself or its descendent objects. Those functions are used by the object itself or its descendent objects.
For example, GObject class is declared in `gobject.h` in GLib source files. For example, GObject class is declared in `gobject.h` in GLib source files.
1 typedef struct _GObjectClass GObjectClass; ~~~C
2 typedef struct _GObjectClass GInitiallyUnownedClass; 1 typedef struct _GObjectClass GObjectClass;
3 2 typedef struct _GObjectClass GInitiallyUnownedClass;
4 struct _GObjectClass { 3
5 GTypeClass g_type_class; 4 struct _GObjectClass {
6 /*< private >*/ 5 GTypeClass g_type_class;
7 GSList *construct_properties; 6 /*< private >*/
8 /*< public >*/ 7 GSList *construct_properties;
9 /* seldom overidden */ 8 /*< public >*/
10 GObject* (*constructor) (GType type, 9 /* seldom overidden */
11 guint n_construct_properties, 10 GObject* (*constructor) (GType type,
12 GObjectConstructParam *construct_properties); 11 guint n_construct_properties,
13 /* overridable methods */ 12 GObjectConstructParam *construct_properties);
14 void (*set_property) (GObject *object, 13 /* overridable methods */
15 guint property_id, 14 void (*set_property) (GObject *object,
16 const GValue *value, 15 guint property_id,
17 GParamSpec *pspec); 16 const GValue *value,
18 void (*get_property) (GObject *object, 17 GParamSpec *pspec);
19 guint property_id, 18 void (*get_property) (GObject *object,
20 GValue *value, 19 guint property_id,
21 GParamSpec *pspec); 20 GValue *value,
22 void (*dispose) (GObject *object); 21 GParamSpec *pspec);
23 void (*finalize) (GObject *object); 22 void (*dispose) (GObject *object);
24 /* seldom overidden */ 23 void (*finalize) (GObject *object);
25 void (*dispatch_properties_changed) (GObject *object, 24 /* seldom overidden */
26 guint n_pspecs, 25 void (*dispatch_properties_changed) (GObject *object,
27 GParamSpec **pspecs); 26 guint n_pspecs,
28 /* signals */ 27 GParamSpec **pspecs);
29 void (*notify) (GObject *object, 28 /* signals */
30 GParamSpec *pspec); 29 void (*notify) (GObject *object,
31 30 GParamSpec *pspec);
32 /* called when done constructing */ 31
33 void (*constructed) (GObject *object); 32 /* called when done constructing */
34 /*< private >*/ 33 void (*constructed) (GObject *object);
35 gsize flags; 34 /*< private >*/
36 /* padding */ 35 gsize flags;
37 gpointer pdummy[6]; 36 /* padding */
38 }; 37 gpointer pdummy[6];
38 };
~~~
I'd like to explain some of the members. I'd like to explain some of the members.
There's a pointer to the function `dispose` in line 22. There's a pointer to the function `dispose` in line 22.
@ -218,114 +224,116 @@ Let's look at all the classes from GObject, which is the top level object, to Tf
The following is extracts from the source files (not exactly the same). The following is extracts from the source files (not exactly the same).
1 struct _GtkWidgetClass { ~~~C
2 GInitiallyUnownedClass parent_class; 1 struct _GtkWidgetClass {
3 /*< public >*/ 2 GInitiallyUnownedClass parent_class;
4 guint activate_signal; 3 /*< public >*/
5 /* basics */ 4 guint activate_signal;
6 void (* show) (GtkWidget *widget); 5 /* basics */
7 void (* hide) (GtkWidget *widget); 6 void (* show) (GtkWidget *widget);
8 void (* map) (GtkWidget *widget); 7 void (* hide) (GtkWidget *widget);
9 void (* unmap) (GtkWidget *widget); 8 void (* map) (GtkWidget *widget);
10 void (* realize) (GtkWidget *widget); 9 void (* unmap) (GtkWidget *widget);
11 void (* unrealize) (GtkWidget *widget); 10 void (* realize) (GtkWidget *widget);
12 void (* root) (GtkWidget *widget); 11 void (* unrealize) (GtkWidget *widget);
13 void (* unroot) (GtkWidget *widget); 12 void (* root) (GtkWidget *widget);
14 void (* size_allocate) (GtkWidget *widget, 13 void (* unroot) (GtkWidget *widget);
15 int width, 14 void (* size_allocate) (GtkWidget *widget,
16 int height, 15 int width,
17 int baseline); 16 int height,
18 void (* state_flags_changed) (GtkWidget *widget, 17 int baseline);
19 GtkStateFlags previous_state_flags); 18 void (* state_flags_changed) (GtkWidget *widget,
20 void (* direction_changed) (GtkWidget *widget, 19 GtkStateFlags previous_state_flags);
21 GtkTextDirection previous_direction); 20 void (* direction_changed) (GtkWidget *widget,
22 void (* grab_notify) (GtkWidget *widget, 21 GtkTextDirection previous_direction);
23 gboolean was_grabbed); 22 void (* grab_notify) (GtkWidget *widget,
24 /* size requests */ 23 gboolean was_grabbed);
25 GtkSizeRequestMode (* get_request_mode) (GtkWidget *widget); 24 /* size requests */
26 void (* measure) (GtkWidget *widget, 25 GtkSizeRequestMode (* get_request_mode) (GtkWidget *widget);
27 GtkOrientation orientation, 26 void (* measure) (GtkWidget *widget,
28 int for_size, 27 GtkOrientation orientation,
29 int *minimum, 28 int for_size,
30 int *natural, 29 int *minimum,
31 int *minimum_baseline, 30 int *natural,
32 int *natural_baseline); 31 int *minimum_baseline,
33 /* Mnemonics */ 32 int *natural_baseline);
34 gboolean (* mnemonic_activate) (GtkWidget *widget, 33 /* Mnemonics */
35 gboolean group_cycling); 34 gboolean (* mnemonic_activate) (GtkWidget *widget,
36 /* explicit focus */ 35 gboolean group_cycling);
37 gboolean (* grab_focus) (GtkWidget *widget); 36 /* explicit focus */
38 gboolean (* focus) (GtkWidget *widget, 37 gboolean (* grab_focus) (GtkWidget *widget);
39 GtkDirectionType direction); 38 gboolean (* focus) (GtkWidget *widget,
40 void (* set_focus_child) (GtkWidget *widget, 39 GtkDirectionType direction);
41 GtkWidget *child); 40 void (* set_focus_child) (GtkWidget *widget,
42 /* keyboard navigation */ 41 GtkWidget *child);
43 void (* move_focus) (GtkWidget *widget, 42 /* keyboard navigation */
44 GtkDirectionType direction); 43 void (* move_focus) (GtkWidget *widget,
45 gboolean (* keynav_failed) (GtkWidget *widget, 44 GtkDirectionType direction);
46 GtkDirectionType direction); 45 gboolean (* keynav_failed) (GtkWidget *widget,
47 /* accessibility support 46 GtkDirectionType direction);
48 */ 47 /* accessibility support
49 AtkObject * (* get_accessible) (GtkWidget *widget); 48 */
50 gboolean (* query_tooltip) (GtkWidget *widget, 49 AtkObject * (* get_accessible) (GtkWidget *widget);
51 gint x, 50 gboolean (* query_tooltip) (GtkWidget *widget,
52 gint y, 51 gint x,
53 gboolean keyboard_tooltip, 52 gint y,
54 GtkTooltip *tooltip); 53 gboolean keyboard_tooltip,
55 void (* compute_expand) (GtkWidget *widget, 54 GtkTooltip *tooltip);
56 gboolean *hexpand_p, 55 void (* compute_expand) (GtkWidget *widget,
57 gboolean *vexpand_p); 56 gboolean *hexpand_p,
58 void (* css_changed) (GtkWidget *widget, 57 gboolean *vexpand_p);
59 GtkCssStyleChange *change); 58 void (* css_changed) (GtkWidget *widget,
60 void (* system_setting_changed) (GtkWidget *widget, 59 GtkCssStyleChange *change);
61 GtkSystemSetting settings); 60 void (* system_setting_changed) (GtkWidget *widget,
62 void (* snapshot) (GtkWidget *widget, 61 GtkSystemSetting settings);
63 GtkSnapshot *snapshot); 62 void (* snapshot) (GtkWidget *widget,
64 gboolean (* contains) (GtkWidget *widget, 63 GtkSnapshot *snapshot);
65 gdouble x, 64 gboolean (* contains) (GtkWidget *widget,
66 gdouble y); 65 gdouble x,
67 /*< private >*/ 66 gdouble y);
68 GtkWidgetClassPrivate *priv; 67 /*< private >*/
69 gpointer padding[8]; 68 GtkWidgetClassPrivate *priv;
70 }; 69 gpointer padding[8];
71 70 };
72 struct _GtkTextViewClass { 71
73 GtkWidgetClass parent_class; 72 struct _GtkTextViewClass {
74 /*< public >*/ 73 GtkWidgetClass parent_class;
75 void (* move_cursor) (GtkTextView *text_view, 74 /*< public >*/
76 GtkMovementStep step, 75 void (* move_cursor) (GtkTextView *text_view,
77 gint count, 76 GtkMovementStep step,
78 gboolean extend_selection); 77 gint count,
79 void (* set_anchor) (GtkTextView *text_view); 78 gboolean extend_selection);
80 void (* insert_at_cursor) (GtkTextView *text_view, 79 void (* set_anchor) (GtkTextView *text_view);
81 const gchar *str); 80 void (* insert_at_cursor) (GtkTextView *text_view,
82 void (* delete_from_cursor) (GtkTextView *text_view, 81 const gchar *str);
83 GtkDeleteType type, 82 void (* delete_from_cursor) (GtkTextView *text_view,
84 gint count); 83 GtkDeleteType type,
85 void (* backspace) (GtkTextView *text_view); 84 gint count);
86 void (* cut_clipboard) (GtkTextView *text_view); 85 void (* backspace) (GtkTextView *text_view);
87 void (* copy_clipboard) (GtkTextView *text_view); 86 void (* cut_clipboard) (GtkTextView *text_view);
88 void (* paste_clipboard) (GtkTextView *text_view); 87 void (* copy_clipboard) (GtkTextView *text_view);
89 void (* toggle_overwrite) (GtkTextView *text_view); 88 void (* paste_clipboard) (GtkTextView *text_view);
90 GtkTextBuffer * (* create_buffer) (GtkTextView *text_view); 89 void (* toggle_overwrite) (GtkTextView *text_view);
91 void (* snapshot_layer) (GtkTextView *text_view, 90 GtkTextBuffer * (* create_buffer) (GtkTextView *text_view);
92 GtkTextViewLayer layer, 91 void (* snapshot_layer) (GtkTextView *text_view,
93 GtkSnapshot *snapshot); 92 GtkTextViewLayer layer,
94 gboolean (* extend_selection) (GtkTextView *text_view, 93 GtkSnapshot *snapshot);
95 GtkTextExtendSelection granularity, 94 gboolean (* extend_selection) (GtkTextView *text_view,
96 const GtkTextIter *location, 95 GtkTextExtendSelection granularity,
97 GtkTextIter *start, 96 const GtkTextIter *location,
98 GtkTextIter *end); 97 GtkTextIter *start,
99 void (* insert_emoji) (GtkTextView *text_view); 98 GtkTextIter *end);
100 /*< private >*/ 99 void (* insert_emoji) (GtkTextView *text_view);
101 gpointer padding[8]; 100 /*< private >*/
102 }; 101 gpointer padding[8];
103 102 };
104 /* The following definition is generated by the macro G_DECLARE_FINAL_TYPE 103
105 typedef struct { 104 /* The following definition is generated by the macro G_DECLARE_FINAL_TYPE
106 GtkTextView parent_class; 105 typedef struct {
107 } TfeTextViewClass; 106 GtkTextView parent_class;
108 107 } TfeTextViewClass;
108
~~~
- 105-107: This three lines are generated by the macro G\_DECLARE\_FINAL\_TYPE. - 105-107: This three lines are generated by the macro G\_DECLARE\_FINAL\_TYPE.
So, they are not written in either `tfe_text_view.h` or `tfe_text_view.c`. So, they are not written in either `tfe_text_view.h` or `tfe_text_view.c`.
@ -370,15 +378,17 @@ In the destruction process of TfeTextView, the reference count of widgets relate
But GFile pointed by `tv->file` needs to decrease its reference count by one. But GFile pointed by `tv->file` needs to decrease its reference count by one.
You must write the code in the dispose handler `tfe_text_view_dispose`. You must write the code in the dispose handler `tfe_text_view_dispose`.
1 static void ~~~C
2 tfe_text_view_dispose (GObject *gobject) { 1 static void
3 TfeTextView *tv = TFE_TEXT_VIEW (gobject); 2 tfe_text_view_dispose (GObject *gobject) {
4 3 TfeTextView *tv = TFE_TEXT_VIEW (gobject);
5 if (G_IS_FILE (tv->file)) 4
6 g_clear_object (&tv->file); 5 if (G_IS_FILE (tv->file))
7 6 g_clear_object (&tv->file);
8 G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject); 7
9 } 8 G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
9 }
~~~
- 5,6: If `tv->file` points a GFile, decrease its reference count. - 5,6: If `tv->file` points a GFile, decrease its reference count.
`g_clear_object` decreases the reference count and assigns NULL to `tv->file`. In dispose handlers, we usually use `g_clear_object` rather than `g_object_unref`. `g_clear_object` decreases the reference count and assigns NULL to `tv->file`. In dispose handlers, we usually use `g_clear_object` rather than `g_object_unref`.

View file

@ -55,33 +55,35 @@ If you need to register two or more signals, static array is usually used.
Signal registration codes are written in the class initialization function. Signal registration codes are written in the class initialization function.
1 static void ~~~C
2 tfe_text_view_class_init (TfeTextViewClass *class) { 1 static void
3 GObjectClass *object_class = G_OBJECT_CLASS (class); 2 tfe_text_view_class_init (TfeTextViewClass *class) {
4 3 GObjectClass *object_class = G_OBJECT_CLASS (class);
5 object_class->dispose = tfe_text_view_dispose; 4
6 tfe_text_view_signals[CHANGE_FILE] = g_signal_newv ("change-file", 5 object_class->dispose = tfe_text_view_dispose;
7 G_TYPE_FROM_CLASS (class), 6 tfe_text_view_signals[CHANGE_FILE] = g_signal_newv ("change-file",
8 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 7 G_TYPE_FROM_CLASS (class),
9 NULL /* closure */, 8 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
10 NULL /* accumulator */, 9 NULL /* closure */,
11 NULL /* accumulator data */, 10 NULL /* accumulator */,
12 NULL /* C marshaller */, 11 NULL /* accumulator data */,
13 G_TYPE_NONE /* return_type */, 12 NULL /* C marshaller */,
14 0 /* n_params */, 13 G_TYPE_NONE /* return_type */,
15 NULL /* param_types */); 14 0 /* n_params */,
16 GType param_types[] = {G_TYPE_INT}; 15 NULL /* param_types */);
17 tfe_text_view_signals[OPEN_RESPONSE] = g_signal_newv ("open-response", 16 GType param_types[] = {G_TYPE_INT};
18 G_TYPE_FROM_CLASS (class), 17 tfe_text_view_signals[OPEN_RESPONSE] = g_signal_newv ("open-response",
19 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 18 G_TYPE_FROM_CLASS (class),
20 NULL /* closure */, 19 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
21 NULL /* accumulator */, 20 NULL /* closure */,
22 NULL /* accumulator data */, 21 NULL /* accumulator */,
23 NULL /* C marshaller */, 22 NULL /* accumulator data */,
24 G_TYPE_NONE /* return_type */, 23 NULL /* C marshaller */,
25 1 /* n_params */, 24 G_TYPE_NONE /* return_type */,
26 param_types); 25 1 /* n_params */,
27 } 26 param_types);
27 }
~~~
- 6-15: Register "change-file"signal. - 6-15: Register "change-file"signal.
`g_signal_newv` function is used. `g_signal_newv` function is used.

View file

@ -9,42 +9,46 @@ In this section I will explain each function in TfeTextView object.
`tfe.h` is a top header file and it includes `gtk.h` and all the header files. `tfe.h` is a top header file and it includes `gtk.h` and all the header files.
Every C source files, which are `tfeapplication.c`, `tfenotebook.c` and `tfetextview.c`, include `tfe.h` at the beginning of each file. Every C source files, which are `tfeapplication.c`, `tfenotebook.c` and `tfetextview.c`, include `tfe.h` at the beginning of each file.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 #include "tfetextview.h" 2
4 #include "tfenotebook.h" 3 #include "tfetextview.h"
4 #include "tfenotebook.h"
~~~
`tfetextview.h` is a header file which describes the public functions in `tfetextview.c`. `tfetextview.h` is a header file which describes the public functions in `tfetextview.c`.
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type () ~~~C
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView) 1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
3 2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
4 /* "open-response" signal response */ 3
5 enum 4 /* "open-response" signal response */
6 { 5 enum
7 TFE_OPEN_RESPONSE_SUCCESS, 6 {
8 TFE_OPEN_RESPONSE_CANCEL, 7 TFE_OPEN_RESPONSE_SUCCESS,
9 TFE_OPEN_RESPONSE_ERROR 8 TFE_OPEN_RESPONSE_CANCEL,
10 }; 9 TFE_OPEN_RESPONSE_ERROR
11 10 };
12 GFile * 11
13 tfe_text_view_get_file (TfeTextView *tv); 12 GFile *
14 13 tfe_text_view_get_file (TfeTextView *tv);
15 void 14
16 tfe_text_view_open (TfeTextView *tv, GtkWidget *win); 15 void
17 16 tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
18 void 17
19 tfe_text_view_save (TfeTextView *tv); 18 void
20 19 tfe_text_view_save (TfeTextView *tv);
21 void 20
22 tfe_text_view_saveas (TfeTextView *tv); 21 void
23 22 tfe_text_view_saveas (TfeTextView *tv);
24 GtkWidget * 23
25 tfe_text_view_new_with_file (GFile *file); 24 GtkWidget *
26 25 tfe_text_view_new_with_file (GFile *file);
27 GtkWidget * 26
28 tfe_text_view_new (void); 27 GtkWidget *
29 28 tfe_text_view_new (void);
29
~~~
- 1-2: These two lines are used to define TfeTextView. - 1-2: These two lines are used to define TfeTextView.
- 4-10: Definitions of parameter used in the handler of "open-response" signal. - 4-10: Definitions of parameter used in the handler of "open-response" signal.
@ -75,30 +79,32 @@ If an error occures during the genration process, NULL is returned.
Each function is defined as follows. Each function is defined as follows.
1 GtkWidget * ~~~C
2 tfe_text_view_new_with_file (GFile *file) { 1 GtkWidget *
3 g_return_val_if_fail (G_IS_FILE (file), NULL); 2 tfe_text_view_new_with_file (GFile *file) {
4 3 g_return_val_if_fail (G_IS_FILE (file), NULL);
5 GtkWidget *tv; 4
6 GtkTextBuffer *tb; 5 GtkWidget *tv;
7 char *contents; 6 GtkTextBuffer *tb;
8 gsize length; 7 char *contents;
9 8 gsize length;
10 if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */ 9
11 return NULL; 10 if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
12 11 return NULL;
13 tv = tfe_text_view_new(); 12
14 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 13 tv = tfe_text_view_new();
15 gtk_text_buffer_set_text (tb, contents, length); 14 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
16 g_free (contents); 15 gtk_text_buffer_set_text (tb, contents, length);
17 TFE_TEXT_VIEW (tv)->file = g_file_dup (file); 16 g_free (contents);
18 return tv; 17 TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
19 } 18 return tv;
20 19 }
21 GtkWidget * 20
22 tfe_text_view_new (void) { 21 GtkWidget *
23 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL)); 22 tfe_text_view_new (void) {
24 } 23 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
24 }
~~~
- 21-24: `tfe_text_view_new`. - 21-24: `tfe_text_view_new`.
Just returns the value from the function `g_object_new` but casted to the pointer to GtkWidget. Just returns the value from the function `g_object_new` but casted to the pointer to GtkWidget.
@ -137,76 +143,78 @@ If `tv->file` is NULL, then it shows GtkFileChooserDialog and lets the user to g
If an error occures, it is shown to the user through the message dialog. If an error occures, it is shown to the user through the message dialog.
The error is managed only in the object and no information is notified to the caller. The error is managed only in the object and no information is notified to the caller.
1 static void ~~~C
2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) { 1 static void
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
4 GFile *file; 3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
5 4 GFile *file;
6 if (response == GTK_RESPONSE_ACCEPT) { 5
7 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); 6 if (response == GTK_RESPONSE_ACCEPT) {
8 if (G_IS_FILE(file)) { 7 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
9 tv->file = file; 8 if (G_IS_FILE(file)) {
10 gtk_text_buffer_set_modified (tb, TRUE); 9 tv->file = file;
11 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0); 10 gtk_text_buffer_set_modified (tb, TRUE);
12 tfe_text_view_save (TFE_TEXT_VIEW (tv)); 11 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
13 } 12 tfe_text_view_save (TFE_TEXT_VIEW (tv));
14 } 13 }
15 gtk_window_destroy (GTK_WINDOW (dialog)); 14 }
16 } 15 gtk_window_destroy (GTK_WINDOW (dialog));
17 16 }
18 void 17
19 tfe_text_view_save (TfeTextView *tv) { 18 void
20 g_return_if_fail (TFE_IS_TEXT_VIEW (tv)); 19 tfe_text_view_save (TfeTextView *tv) {
21 20 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
22 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 21
23 GtkTextIter start_iter; 22 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
24 GtkTextIter end_iter; 23 GtkTextIter start_iter;
25 gchar *contents; 24 GtkTextIter end_iter;
26 GtkWidget *message_dialog; 25 gchar *contents;
27 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW); 26 GtkWidget *message_dialog;
28 GError *err = NULL; 27 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
29 28 GError *err = NULL;
30 if (! gtk_text_buffer_get_modified (tb)) 29
31 return; /* no necessary to save it */ 30 if (! gtk_text_buffer_get_modified (tb))
32 else if (tv->file == NULL) 31 return; /* no necessary to save it */
33 tfe_text_view_saveas (tv); 32 else if (tv->file == NULL)
34 else { 33 tfe_text_view_saveas (tv);
35 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter); 34 else {
36 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE); 35 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
37 if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err)) 36 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
38 gtk_text_buffer_set_modified (tb, FALSE); 37 if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err))
39 else { 38 gtk_text_buffer_set_modified (tb, FALSE);
40 /* It is possible that tv->file is broken. */ 39 else {
41 /* It is a good idea to set tv->file to NULL. */ 40 /* It is possible that tv->file is broken. */
42 if (G_IS_FILE (tv->file)) 41 /* It is a good idea to set tv->file to NULL. */
43 g_object_unref (tv->file); 42 if (G_IS_FILE (tv->file))
44 tv->file =NULL; 43 g_object_unref (tv->file);
45 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0); 44 tv->file =NULL;
46 gtk_text_buffer_set_modified (tb, TRUE); 45 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
47 message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL, 46 gtk_text_buffer_set_modified (tb, TRUE);
48 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, 47 message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
49 "%s.\n", err->message); 48 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
50 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL); 49 "%s.\n", err->message);
51 gtk_widget_show (message_dialog); 50 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
52 g_error_free (err); 51 gtk_widget_show (message_dialog);
53 } 52 g_error_free (err);
54 } 53 }
55 } 54 }
56 55 }
57 void 56
58 tfe_text_view_saveas (TfeTextView *tv) { 57 void
59 g_return_if_fail (TFE_IS_TEXT_VIEW (tv)); 58 tfe_text_view_saveas (TfeTextView *tv) {
60 59 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
61 GtkWidget *dialog; 60
62 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW); 61 GtkWidget *dialog;
63 62 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
64 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE, 63
65 "_Cancel", GTK_RESPONSE_CANCEL, 64 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
66 "_Save", GTK_RESPONSE_ACCEPT, 65 "_Cancel", GTK_RESPONSE_CANCEL,
67 NULL); 66 "_Save", GTK_RESPONSE_ACCEPT,
68 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv); 67 NULL);
69 gtk_widget_show (dialog); 68 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
70 } 69 gtk_widget_show (dialog);
70 }
~~~
- 18-55: `Tfe_text_view_save` function. - 18-55: `Tfe_text_view_save` function.
- 20: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns. - 20: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns.
@ -258,55 +266,57 @@ Otherwise probably bad things will happen.
GtkWidget `win` is expected to be the top level window of the application. GtkWidget `win` is expected to be the top level window of the application.
It will be used as a transient parent window for the argument to the function `gtk_file_chooser_dialog_new`. It will be used as a transient parent window for the argument to the function `gtk_file_chooser_dialog_new`.
1 static void ~~~C
2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) { 1 static void
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
4 GFile *file; 3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
5 char *contents; 4 GFile *file;
6 gsize length; 5 char *contents;
7 GtkWidget *message_dialog; 6 gsize length;
8 GError *err = NULL; 7 GtkWidget *message_dialog;
9 8 GError *err = NULL;
10 if (response != GTK_RESPONSE_ACCEPT) 9
11 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL); 10 if (response != GTK_RESPONSE_ACCEPT)
12 else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)))) 11 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
13 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR); 12 else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog))))
14 else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */ 13 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
15 if (G_IS_FILE (file)) 14 else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
16 g_object_unref (file); 15 if (G_IS_FILE (file))
17 message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL, 16 g_object_unref (file);
18 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, 17 message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
19 "%s.\n", err->message); 18 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
20 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL); 19 "%s.\n", err->message);
21 gtk_widget_show (message_dialog); 20 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
22 g_error_free (err); 21 gtk_widget_show (message_dialog);
23 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR); 22 g_error_free (err);
24 } else { 23 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
25 gtk_text_buffer_set_text (tb, contents, length); 24 } else {
26 g_free (contents); 25 gtk_text_buffer_set_text (tb, contents, length);
27 if (G_IS_FILE (tv->file)) 26 g_free (contents);
28 g_object_unref (tv->file); 27 if (G_IS_FILE (tv->file))
29 tv->file = file; 28 g_object_unref (tv->file);
30 gtk_text_buffer_set_modified (tb, FALSE); 29 tv->file = file;
31 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS); 30 gtk_text_buffer_set_modified (tb, FALSE);
32 } 31 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
33 gtk_window_destroy (GTK_WINDOW (dialog)); 32 }
34 } 33 gtk_window_destroy (GTK_WINDOW (dialog));
35 34 }
36 void 35
37 tfe_text_view_open (TfeTextView *tv, GtkWidget *win) { 36 void
38 g_return_if_fail (TFE_IS_TEXT_VIEW (tv)); 37 tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
39 g_return_if_fail (GTK_IS_WINDOW (win)); 38 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
40 39 g_return_if_fail (GTK_IS_WINDOW (win));
41 GtkWidget *dialog; 40
42 41 GtkWidget *dialog;
43 dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN, 42
44 "Cancel", GTK_RESPONSE_CANCEL, 43 dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
45 "Open", GTK_RESPONSE_ACCEPT, 44 "Cancel", GTK_RESPONSE_CANCEL,
46 NULL); 45 "Open", GTK_RESPONSE_ACCEPT,
47 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv); 46 NULL);
48 gtk_widget_show (dialog); 47 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
49 } 48 gtk_widget_show (dialog);
49 }
~~~
- 36-49: `tfe_text_view_open` function. - 36-49: `tfe_text_view_open` function.
- 43: Generate GtkFileChooserDialog. - 43: Generate GtkFileChooserDialog.
@ -345,12 +355,14 @@ However, in Gtk4, `gtk_dialog_run`is unavailable any more.
`gtk_text_view_get_file` is a simple function show as follows. `gtk_text_view_get_file` is a simple function show as follows.
1 GFile * ~~~C
2 tfe_text_view_get_file (TfeTextView *tv) { 1 GFile *
3 g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL); 2 tfe_text_view_get_file (TfeTextView *tv) {
4 3 g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
5 return g_file_dup (tv->file); 4
6 } 5 return g_file_dup (tv->file);
6 }
~~~
The important thing is duplicate `tv->file`. The important thing is duplicate `tv->file`.
Otherwise, if the caller free the GFile object, `tv->file` is no more guaranteed to point the GFile. Otherwise, if the caller free the GFile object, `tv->file` is no more guaranteed to point the GFile.

View file

@ -6,18 +6,20 @@ GtkNotebook is a very important object in the text file editor `tfe`.
It connects the application and TfeTextView objects. It connects the application and TfeTextView objects.
`tfenotebook.h` and `tfenotebook.c` have a set of functions related to GtkTextbook. `tfenotebook.h` and `tfenotebook.c` have a set of functions related to GtkTextbook.
1 void ~~~C
2 notebook_page_save(GtkNotebook *nb); 1 void
3 2 notebook_page_save(GtkNotebook *nb);
4 void 3
5 notebook_page_open (GtkNotebook *nb); 4 void
6 5 notebook_page_open (GtkNotebook *nb);
7 void 6
8 notebook_page_new_with_file (GtkNotebook *nb, GFile *file); 7 void
9 8 notebook_page_new_with_file (GtkNotebook *nb, GFile *file);
10 void 9
11 notebook_page_new (GtkNotebook *nb); 10 void
12 11 notebook_page_new (GtkNotebook *nb);
12
~~~
This header file shows the public functions in `tfenotebook.c`. This header file shows the public functions in `tfenotebook.c`.
@ -44,43 +46,45 @@ Now let's look at each program of the functions.
## notebook\_page\_new ## notebook\_page\_new
1 static gchar* ~~~C
2 get_untitled () { 1 static gchar*
3 static int c = -1; 2 get_untitled () {
4 if (++c == 0) 3 static int c = -1;
5 return g_strdup_printf("Untitled"); 4 if (++c == 0)
6 else 5 return g_strdup_printf("Untitled");
7 return g_strdup_printf ("Untitled%u", c); 6 else
8 } 7 return g_strdup_printf ("Untitled%u", c);
9 8 }
10 static void 9
11 notebook_page_build (GtkNotebook *nb, GtkWidget *tv, char *filename) { 10 static void
12 GtkWidget *scr; 11 notebook_page_build (GtkNotebook *nb, GtkWidget *tv, char *filename) {
13 GtkNotebookPage *nbp; 12 GtkWidget *scr;
14 GtkWidget *lab; 13 GtkNotebookPage *nbp;
15 gint i; 14 GtkWidget *lab;
16 scr = gtk_scrolled_window_new (); 15 gint i;
17 16 scr = gtk_scrolled_window_new ();
18 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 17
19 lab = gtk_label_new (filename); 18 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
20 i = gtk_notebook_append_page (nb, scr, lab); 19 lab = gtk_label_new (filename);
21 nbp = gtk_notebook_get_page (nb, scr); 20 i = gtk_notebook_append_page (nb, scr, lab);
22 g_object_set (nbp, "tab-expand", TRUE, NULL); 21 nbp = gtk_notebook_get_page (nb, scr);
23 gtk_notebook_set_current_page (nb, i); 22 g_object_set (nbp, "tab-expand", TRUE, NULL);
24 g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed), nb); 23 gtk_notebook_set_current_page (nb, i);
25 } 24 g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed), nb);
26 25 }
27 void 26
28 notebook_page_new (GtkNotebook *nb) { 27 void
29 g_return_if_fail(GTK_IS_NOTEBOOK (nb)); 28 notebook_page_new (GtkNotebook *nb) {
30 29 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
31 GtkWidget *tv; 30
32 char *filename; 31 GtkWidget *tv;
33 32 char *filename;
34 tv = tfe_text_view_new (); 33
35 filename = get_untitled (); 34 tv = tfe_text_view_new ();
36 notebook_page_build (nb, tv, filename); 35 filename = get_untitled ();
37 } 36 notebook_page_build (nb, tv, filename);
37 }
~~~
- 27-37: `notebook_page_new` function. - 27-37: `notebook_page_new` function.
- 29: `g_return_if_fail` is used to check the argument. - 29: `g_return_if_fail` is used to check the argument.
@ -102,19 +106,21 @@ The caller of `get_untitled` is in charge of freeing the memories of the string.
## notebook\_page\_new\_with\_file ## notebook\_page\_new\_with\_file
1 void ~~~C
2 notebook_page_new_with_file (GtkNotebook *nb, GFile *file) { 1 void
3 g_return_if_fail(GTK_IS_NOTEBOOK (nb)); 2 notebook_page_new_with_file (GtkNotebook *nb, GFile *file) {
4 g_return_if_fail(G_IS_FILE (file)); 3 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
5 4 g_return_if_fail(G_IS_FILE (file));
6 GtkWidget *tv; 5
7 char *filename; 6 GtkWidget *tv;
8 7 char *filename;
9 if ((tv = tfe_text_view_new_with_file (file)) == NULL) 8
10 return; /* read error */ 9 if ((tv = tfe_text_view_new_with_file (file)) == NULL)
11 filename = g_file_get_basename (file); 10 return; /* read error */
12 notebook_page_build (nb, tv, filename); 11 filename = g_file_get_basename (file);
13 } 12 notebook_page_build (nb, tv, filename);
13 }
~~~
- 9-10: Call `tfe_text_view_new_with_file`. - 9-10: Call `tfe_text_view_new_with_file`.
If it returns NULL, then do nothing and return because of an error. If it returns NULL, then do nothing and return because of an error.
@ -122,34 +128,36 @@ If it returns NULL, then do nothing and return because of an error.
## notebook\_page\_open ## notebook\_page\_open
1 static void ~~~C
2 open_response (TfeTextView *tv, gint response, GtkNotebook *nb) { 1 static void
3 GFile *file; 2 open_response (TfeTextView *tv, gint response, GtkNotebook *nb) {
4 char *filename; 3 GFile *file;
5 4 char *filename;
6 if (response != TFE_OPEN_RESPONSE_SUCCESS) { 5
7 g_object_ref_sink (tv); 6 if (response != TFE_OPEN_RESPONSE_SUCCESS) {
8 g_object_unref (tv); 7 g_object_ref_sink (tv);
9 }else if (! G_IS_FILE (file = tfe_text_view_get_file (tv))) { 8 g_object_unref (tv);
10 g_object_ref_sink (tv); 9 }else if (! G_IS_FILE (file = tfe_text_view_get_file (tv))) {
11 g_object_unref (tv); 10 g_object_ref_sink (tv);
12 }else { 11 g_object_unref (tv);
13 filename = g_file_get_basename (file); 12 }else {
14 g_object_unref (file); 13 filename = g_file_get_basename (file);
15 notebook_page_build (nb, GTK_WIDGET (tv), filename); 14 g_object_unref (file);
16 } 15 notebook_page_build (nb, GTK_WIDGET (tv), filename);
17 } 16 }
18 17 }
19 void 18
20 notebook_page_open (GtkNotebook *nb) { 19 void
21 g_return_if_fail(GTK_IS_NOTEBOOK (nb)); 20 notebook_page_open (GtkNotebook *nb) {
22 21 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
23 GtkWidget *tv; 22
24 23 GtkWidget *tv;
25 tv = tfe_text_view_new (); 24
26 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb); 25 tv = tfe_text_view_new ();
27 tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)); 26 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
28 } 27 tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
28 }
~~~
- 19-28: `notebook_page_open` function. - 19-28: `notebook_page_open` function.
- 25: Generate TfeTextView object. - 25: Generate TfeTextView object.
@ -169,17 +177,19 @@ Get the filename, build the contents of the page.
## notebook\_page\_save ## notebook\_page\_save
1 void ~~~C
2 notebook_page_save(GtkNotebook *nb) { 1 void
3 gint i; 2 notebook_page_save(GtkNotebook *nb) {
4 GtkWidget *scr; 3 gint i;
5 GtkWidget *tv; 4 GtkWidget *scr;
6 5 GtkWidget *tv;
7 i = gtk_notebook_get_current_page (nb); 6
8 scr = gtk_notebook_get_nth_page (nb, i); 7 i = gtk_notebook_get_current_page (nb);
9 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr)); 8 scr = gtk_notebook_get_nth_page (nb, i);
10 tfe_text_view_save (TFE_TEXT_VIEW (tv)); 9 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
11 } 10 tfe_text_view_save (TFE_TEXT_VIEW (tv));
11 }
~~~
- 7-9: Get TfeTextView belongs to the current notebook page. - 7-9: Get TfeTextView belongs to the current notebook page.
- 10: Call `tfe_text_view_save`. - 10: Call `tfe_text_view_save`.
@ -190,24 +200,26 @@ The function `file_changed` is a handler connected to "change-file" signal.
If `tv->file` is changed, TfeTextView emits this signal. If `tv->file` is changed, TfeTextView emits this signal.
This handler changes the label of GtkNotebookPage. This handler changes the label of GtkNotebookPage.
1 static void ~~~C
2 file_changed (TfeTextView *tv, GtkNotebook *nb) { 1 static void
3 GFile *file; 2 file_changed (TfeTextView *tv, GtkNotebook *nb) {
4 char *filename; 3 GFile *file;
5 GtkWidget *scr; 4 char *filename;
6 GtkWidget *label; 5 GtkWidget *scr;
7 6 GtkWidget *label;
8 file = tfe_text_view_get_file (tv); 7
9 scr = gtk_widget_get_parent (GTK_WIDGET (tv)); 8 file = tfe_text_view_get_file (tv);
10 if (G_IS_FILE (file)) 9 scr = gtk_widget_get_parent (GTK_WIDGET (tv));
11 filename = g_file_get_basename (file); 10 if (G_IS_FILE (file))
12 else 11 filename = g_file_get_basename (file);
13 filename = get_untitled (); 12 else
14 label = gtk_label_new (filename); 13 filename = get_untitled ();
15 gtk_notebook_set_tab_label (nb, scr, label); 14 label = gtk_label_new (filename);
16 g_object_unref (file); 15 gtk_notebook_set_tab_label (nb, scr, label);
17 g_free (filename); 16 g_object_unref (file);
18 } 17 g_free (filename);
18 }
~~~
- 8: Get GFile from TfeTextView. - 8: Get GFile from TfeTextView.
- 9: Get GkScrolledWindow which is the parent widget of `tv`. - 9: Get GkScrolledWindow which is the parent widget of `tv`.

View file

@ -15,21 +15,23 @@ It does following things.
Th function `main` is the first invoked function in C language. Th function `main` is the first invoked function in C language.
It connects the command line given by the user and GTK application. It connects the command line given by the user and GTK application.
1 int ~~~C
2 main (int argc, char **argv) { 1 int
3 GtkApplication *app; 2 main (int argc, char **argv) {
4 int stat; 3 GtkApplication *app;
5 4 int stat;
6 app = gtk_application_new ("com.github.ToshioCP.tfe", G_APPLICATION_HANDLES_OPEN); 5
7 6 app = gtk_application_new ("com.github.ToshioCP.tfe", G_APPLICATION_HANDLES_OPEN);
8 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL); 7
9 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL); 8 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
10 g_signal_connect (app, "open", G_CALLBACK (tfe_open), NULL); 9 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
11 10 g_signal_connect (app, "open", G_CALLBACK (tfe_open), NULL);
12 stat =g_application_run (G_APPLICATION (app), argc, argv); 11
13 g_object_unref (app); 12 stat =g_application_run (G_APPLICATION (app), argc, argv);
14 return stat; 13 g_object_unref (app);
15 } 14 return stat;
15 }
~~~
- 6: Generate GtkApplication object. - 6: Generate GtkApplication object.
- 8-10: Connect "startup", "activate" and "open signals to their handlers. - 8-10: Connect "startup", "activate" and "open signals to their handlers.
@ -47,38 +49,40 @@ What the signal handler needs to do is initialization of the application.
The handler is as follows. The handler is as follows.
1 static void ~~~C
2 tfe_startup (GApplication *application) { 1 static void
3 GtkApplication *app = GTK_APPLICATION (application); 2 tfe_startup (GApplication *application) {
4 GtkApplicationWindow *win; 3 GtkApplication *app = GTK_APPLICATION (application);
5 GtkNotebook *nb; 4 GtkApplicationWindow *win;
6 GtkBuilder *build; 5 GtkNotebook *nb;
7 GtkButton *btno; 6 GtkBuilder *build;
8 GtkButton *btnn; 7 GtkButton *btno;
9 GtkButton *btns; 8 GtkButton *btnn;
10 GtkButton *btnc; 9 GtkButton *btns;
11 10 GtkButton *btnc;
12 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe/tfe.ui"); 11
13 win = GTK_APPLICATION_WINDOW (gtk_builder_get_object (build, "win")); 12 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe/tfe.ui");
14 nb = GTK_NOTEBOOK (gtk_builder_get_object (build, "nb")); 13 win = GTK_APPLICATION_WINDOW (gtk_builder_get_object (build, "win"));
15 gtk_window_set_application (GTK_WINDOW (win), app); 14 nb = GTK_NOTEBOOK (gtk_builder_get_object (build, "nb"));
16 btno = GTK_BUTTON (gtk_builder_get_object (build, "btno")); 15 gtk_window_set_application (GTK_WINDOW (win), app);
17 btnn = GTK_BUTTON (gtk_builder_get_object (build, "btnn")); 16 btno = GTK_BUTTON (gtk_builder_get_object (build, "btno"));
18 btns = GTK_BUTTON (gtk_builder_get_object (build, "btns")); 17 btnn = GTK_BUTTON (gtk_builder_get_object (build, "btnn"));
19 btnc = GTK_BUTTON (gtk_builder_get_object (build, "btnc")); 18 btns = GTK_BUTTON (gtk_builder_get_object (build, "btns"));
20 g_signal_connect (btno, "clicked", G_CALLBACK (open_clicked), nb); 19 btnc = GTK_BUTTON (gtk_builder_get_object (build, "btnc"));
21 g_signal_connect (btnn, "clicked", G_CALLBACK (new_clicked), nb); 20 g_signal_connect (btno, "clicked", G_CALLBACK (open_clicked), nb);
22 g_signal_connect (btns, "clicked", G_CALLBACK (save_clicked), nb); 21 g_signal_connect (btnn, "clicked", G_CALLBACK (new_clicked), nb);
23 g_signal_connect (btnc, "clicked", G_CALLBACK (close_clicked), nb); 22 g_signal_connect (btns, "clicked", G_CALLBACK (save_clicked), nb);
24 g_object_unref(build); 23 g_signal_connect (btnc, "clicked", G_CALLBACK (close_clicked), nb);
25 24 g_object_unref(build);
26 GdkDisplay *display; 25
27 26 GdkDisplay *display;
28 display = gtk_widget_get_display (GTK_WIDGET (win)); 27
29 GtkCssProvider *provider = gtk_css_provider_new (); 28 display = gtk_widget_get_display (GTK_WIDGET (win));
30 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1); 29 GtkCssProvider *provider = gtk_css_provider_new ();
31 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER); 30 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
32 } 31 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
32 }
~~~
- 12-15: Build widgets using ui file (resource). - 12-15: Build widgets using ui file (resource).
Connect the top window and the application using `gtk_window_set_application`. Connect the top window and the application using `gtk_window_set_application`.
@ -168,39 +172,41 @@ CSS set to the context takes precedence over the one set to the display.
The handler of "activate" and "open" signal are `tfe_activate` and `tfe_open` respectively. The handler of "activate" and "open" signal are `tfe_activate` and `tfe_open` respectively.
They just generate a new GtkNotebookPage. They just generate a new GtkNotebookPage.
1 static void ~~~C
2 tfe_activate (GApplication *application) { 1 static void
3 GtkApplication *app = GTK_APPLICATION (application); 2 tfe_activate (GApplication *application) {
4 GtkWidget *win; 3 GtkApplication *app = GTK_APPLICATION (application);
5 GtkWidget *boxv; 4 GtkWidget *win;
6 GtkNotebook *nb; 5 GtkWidget *boxv;
7 6 GtkNotebook *nb;
8 win = GTK_WIDGET (gtk_application_get_active_window (app)); 7
9 boxv = gtk_window_get_child (GTK_WINDOW (win)); 8 win = GTK_WIDGET (gtk_application_get_active_window (app));
10 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv)); 9 boxv = gtk_window_get_child (GTK_WINDOW (win));
11 10 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
12 notebook_page_new (nb); 11
13 gtk_widget_show (GTK_WIDGET (win)); 12 notebook_page_new (nb);
14 } 13 gtk_widget_show (GTK_WIDGET (win));
15 14 }
16 static void 15
17 tfe_open (GApplication *application, GFile ** files, gint n_files, const gchar *hint) { 16 static void
18 GtkApplication *app = GTK_APPLICATION (application); 17 tfe_open (GApplication *application, GFile ** files, gint n_files, const gchar *hint) {
19 GtkWidget *win; 18 GtkApplication *app = GTK_APPLICATION (application);
20 GtkWidget *boxv; 19 GtkWidget *win;
21 GtkNotebook *nb; 20 GtkWidget *boxv;
22 int i; 21 GtkNotebook *nb;
23 22 int i;
24 win = GTK_WIDGET (gtk_application_get_active_window (app)); 23
25 boxv = gtk_window_get_child (GTK_WINDOW (win)); 24 win = GTK_WIDGET (gtk_application_get_active_window (app));
26 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv)); 25 boxv = gtk_window_get_child (GTK_WINDOW (win));
27 26 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
28 for (i = 0; i < n_files; i++) 27
29 notebook_page_new_with_file (nb, files[i]); 28 for (i = 0; i < n_files; i++)
30 if (gtk_notebook_get_n_pages (nb) == 0) 29 notebook_page_new_with_file (nb, files[i]);
31 notebook_page_new (nb); 30 if (gtk_notebook_get_n_pages (nb) == 0)
32 gtk_widget_show (win); 31 notebook_page_new (nb);
33 } 32 gtk_widget_show (win);
33 }
~~~
- 1-14: `tfe_activate`. - 1-14: `tfe_activate`.
- 8-10: Get GtkNotebook object. - 8-10: Get GtkNotebook object.
@ -249,36 +255,38 @@ The second instance immediately quits so shell prompt soon appears.
## a series of handlers correspond to the button signals ## a series of handlers correspond to the button signals
1 static void ~~~C
2 open_clicked (GtkWidget *btno, GtkNotebook *nb) { 1 static void
3 notebook_page_open (nb); 2 open_clicked (GtkWidget *btno, GtkNotebook *nb) {
4 } 3 notebook_page_open (nb);
5 4 }
6 static void 5
7 new_clicked (GtkWidget *btnn, GtkNotebook *nb) { 6 static void
8 notebook_page_new (nb); 7 new_clicked (GtkWidget *btnn, GtkNotebook *nb) {
9 } 8 notebook_page_new (nb);
10 9 }
11 static void 10
12 save_clicked (GtkWidget *btns, GtkNotebook *nb) { 11 static void
13 notebook_page_save (nb); 12 save_clicked (GtkWidget *btns, GtkNotebook *nb) {
14 } 13 notebook_page_save (nb);
15 14 }
16 static void 15
17 close_clicked (GtkWidget *btnc, GtkNotebook *nb) { 16 static void
18 GtkWidget *win; 17 close_clicked (GtkWidget *btnc, GtkNotebook *nb) {
19 GtkWidget *boxv; 18 GtkWidget *win;
20 gint i; 19 GtkWidget *boxv;
21 20 gint i;
22 if (gtk_notebook_get_n_pages (nb) == 1) { 21
23 boxv = gtk_widget_get_parent (GTK_WIDGET (nb)); 22 if (gtk_notebook_get_n_pages (nb) == 1) {
24 win = gtk_widget_get_parent (boxv); 23 boxv = gtk_widget_get_parent (GTK_WIDGET (nb));
25 gtk_window_destroy (GTK_WINDOW (win)); 24 win = gtk_widget_get_parent (boxv);
26 } else { 25 gtk_window_destroy (GTK_WINDOW (win));
27 i = gtk_notebook_get_current_page (nb); 26 } else {
28 gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i); 27 i = gtk_notebook_get_current_page (nb);
29 } 28 gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
30 } 29 }
30 }
~~~
`open_clicked`, `new_clicked` and `save_clicked` just call corresponding notebook page functions. `open_clicked`, `new_clicked` and `save_clicked` just call corresponding notebook page functions.
`close_clicked` is a bit complicated. `close_clicked` is a bit complicated.
@ -289,16 +297,18 @@ First, get the top level window and call `gtk_window_destroy`.
## meson.build ## meson.build
1 project('tfe', 'c') ~~~meson
2 1 project('tfe', 'c')
3 gtkdep = dependency('gtk4') 2
4 3 gtkdep = dependency('gtk4')
5 gnome=import('gnome') 4
6 resources = gnome.compile_resources('resources','tfe.gresource.xml') 5 gnome=import('gnome')
7 6 resources = gnome.compile_resources('resources','tfe.gresource.xml')
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c') 7
9 8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep) 9
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
~~~
In this file, just the source file names are modified. In this file, just the source file names are modified.

File diff suppressed because it is too large Load diff

View file

@ -119,53 +119,55 @@ So, if the action is activated, the handler will be invoked.
The following is a simple example of menus and actions. The following is a simple example of menus and actions.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app) 3 static void
5 { 4 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
6 g_application_quit (G_APPLICATION(app)); 5 {
7 } 6 g_application_quit (G_APPLICATION(app));
8 7 }
9 static void 8
10 on_activate (GApplication *app, gpointer user_data) { 9 static void
11 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app)); 10 on_activate (GApplication *app, gpointer user_data) {
12 gtk_window_set_title (GTK_WINDOW (win), "menu1"); 11 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
13 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 12 gtk_window_set_title (GTK_WINDOW (win), "menu1");
14 13 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
15 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL); 14
16 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit)); 15 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
17 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app); 16 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
18 17 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
19 GMenu *menubar = g_menu_new (); 18
20 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL); 19 GMenu *menubar = g_menu_new ();
21 GMenu *menu = g_menu_new (); 20 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
22 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit"); 21 GMenu *menu = g_menu_new ();
23 g_menu_append_item (menu, menu_item_quit); 22 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
24 g_object_unref (menu_item_quit); 23 g_menu_append_item (menu, menu_item_quit);
25 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu)); 24 g_object_unref (menu_item_quit);
26 g_menu_append_item (menubar, menu_item_menu); 25 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
27 g_object_unref (menu_item_menu); 26 g_menu_append_item (menubar, menu_item_menu);
28 27 g_object_unref (menu_item_menu);
29 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar)); 28
30 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE); 29 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
31 gtk_window_present (GTK_WINDOW (win)); 30 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
32 /* gtk_widget_show (win); is also OKay instead of gtk_window_present. */ 31 gtk_window_present (GTK_WINDOW (win));
33 } 32 /* gtk_widget_show (win); is also OKay instead of gtk_window_present. */
34 33 }
35 int 34
36 main (int argc, char **argv) { 35 int
37 GtkApplication *app; 36 main (int argc, char **argv) {
38 int stat; 37 GtkApplication *app;
39 38 int stat;
40 app = gtk_application_new ("com.github.ToshioCP.menu1", G_APPLICATION_FLAGS_NONE); 39
41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 40 app = gtk_application_new ("com.github.ToshioCP.menu1", G_APPLICATION_FLAGS_NONE);
42 41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
43 stat =g_application_run (G_APPLICATION (app), argc, argv); 42
44 g_object_unref (app); 43 stat =g_application_run (G_APPLICATION (app), argc, argv);
45 return stat; 44 g_object_unref (app);
46 } 45 return stat;
47 46 }
47
~~~
- 3-7: `quit_activated` is a handler of an action `act_quit`. - 3-7: `quit_activated` is a handler of an action `act_quit`.
Handlers of actions have three parameters. Handlers of actions have three parameters.

View file

@ -21,7 +21,8 @@ The signal handler will be described after the explanation of this code.
static void static void
on_activate (GApplication *app, gpointer user_data) { on_activate (GApplication *app, gpointer user_data) {
... ... ... ... ... ...
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE)); GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
NULL, g_variant_new_boolean (FALSE));
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen"); GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win); g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
... ... ... ... ... ...
@ -116,7 +117,8 @@ Those colors are given to the signal handler as a parameter.
static void static void
on_activate (GApplication *app, gpointer user_data) { on_activate (GApplication *app, gpointer user_data) {
... ... ... ... ... ...
GSimpleAction *act_color = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red")); GSimpleAction *act_color = g_simple_action_new_stateful ("color",
g_variant_type_new("s"), g_variant_new_string ("red"));
GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red"); GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green"); GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue"); GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
@ -150,7 +152,8 @@ The following is the "activate" signal handler.
static void static void
color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) { color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
gchar *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL)); gchar *color = g_strdup_printf ("label#lb {background-color: %s;}",
g_variant_get_string (parameter, NULL));
gtk_css_provider_load_from_data (provider, color, -1); gtk_css_provider_load_from_data (provider, color, -1);
g_free (color); g_free (color);
g_action_change_state (G_ACTION (action), parameter); g_action_change_state (G_ACTION (action), parameter);
@ -187,14 +190,16 @@ When GVariantType is generated, the type is expressed by the string.
The following program is a simple example. The following program is a simple example.
It finally output the string "s". It finally output the string "s".
1 #include <glib.h> ~~~C
2 1 #include <glib.h>
3 int 2
4 main (int argc, char **argv) { 3 int
5 GVariantType *vtype = g_variant_type_new ("s"); 4 main (int argc, char **argv) {
6 const gchar *type_string = g_variant_type_peek_string (vtype); 5 GVariantType *vtype = g_variant_type_new ("s");
7 g_print ("%s\n",type_string); 6 const gchar *type_string = g_variant_type_peek_string (vtype);
8 } 7 g_print ("%s\n",type_string);
8 }
~~~
- `g_variant_tpe_new` generates GVariantType. - `g_variant_tpe_new` generates GVariantType.
It uses a type string "s" which means string. It uses a type string "s" which means string.
@ -217,111 +222,113 @@ And the radio button of the selected menu turns on.
The code is as follows. The code is as follows.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static GtkCssProvider *provider; 2
4 3 static GtkCssProvider *provider;
5 static void 4
6 fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) { 5 static void
7 if (g_variant_get_boolean (value)) 6 fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
8 gtk_window_maximize (GTK_WINDOW (win)); 7 if (g_variant_get_boolean (value))
9 else 8 gtk_window_maximize (GTK_WINDOW (win));
10 gtk_window_unmaximize (GTK_WINDOW (win)); 9 else
11 g_simple_action_set_state (action, value); 10 gtk_window_unmaximize (GTK_WINDOW (win));
12 } 11 g_simple_action_set_state (action, value);
13 12 }
14 static void 13
15 color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) { 14 static void
16 gchar *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL)); 15 color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
17 gtk_css_provider_load_from_data (provider, color, -1); 16 gchar *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
18 g_free (color); 17 gtk_css_provider_load_from_data (provider, color, -1);
19 g_action_change_state (G_ACTION (action), parameter); 18 g_free (color);
20 } 19 g_action_change_state (G_ACTION (action), parameter);
21 20 }
22 static void 21
23 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app) 22 static void
24 { 23 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
25 g_application_quit (G_APPLICATION(app)); 24 {
26 } 25 g_application_quit (G_APPLICATION(app));
27 26 }
28 static void 27
29 on_activate (GApplication *app, gpointer user_data) { 28 static void
30 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app)); 29 on_activate (GApplication *app, gpointer user_data) {
31 gtk_window_set_title (GTK_WINDOW (win), "menu2"); 30 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
32 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 31 gtk_window_set_title (GTK_WINDOW (win), "menu2");
33 32 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
34 GtkWidget *lb = gtk_label_new (NULL); 33
35 gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */ 34 GtkWidget *lb = gtk_label_new (NULL);
36 gtk_window_set_child (GTK_WINDOW (win), lb); 35 gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */
37 36 gtk_window_set_child (GTK_WINDOW (win), lb);
38 GSimpleAction *act_fullscreen 37
39 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE)); 38 GSimpleAction *act_fullscreen
40 GSimpleAction *act_color 39 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
41 = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red")); 40 GSimpleAction *act_color
42 GSimpleAction *act_quit 41 = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
43 = g_simple_action_new ("quit", NULL); 42 GSimpleAction *act_quit
44 43 = g_simple_action_new ("quit", NULL);
45 GMenu *menubar = g_menu_new (); 44
46 GMenu *menu = g_menu_new (); 45 GMenu *menubar = g_menu_new ();
47 GMenu *section1 = g_menu_new (); 46 GMenu *menu = g_menu_new ();
48 GMenu *section2 = g_menu_new (); 47 GMenu *section1 = g_menu_new ();
49 GMenu *section3 = g_menu_new (); 48 GMenu *section2 = g_menu_new ();
50 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen"); 49 GMenu *section3 = g_menu_new ();
51 GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red"); 50 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
52 GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green"); 51 GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
53 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue"); 52 GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
54 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit"); 53 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
55 54 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
56 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win); 55
57 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win); 56 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
58 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app); 57 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
59 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen)); 58 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
60 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color)); 59 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit)); 60 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color));
62 61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
63 g_menu_append_item (section1, menu_item_fullscreen); 62
64 g_menu_append_item (section2, menu_item_red); 63 g_menu_append_item (section1, menu_item_fullscreen);
65 g_menu_append_item (section2, menu_item_green); 64 g_menu_append_item (section2, menu_item_red);
66 g_menu_append_item (section2, menu_item_blue); 65 g_menu_append_item (section2, menu_item_green);
67 g_menu_append_item (section3, menu_item_quit); 66 g_menu_append_item (section2, menu_item_blue);
68 g_object_unref (menu_item_red); 67 g_menu_append_item (section3, menu_item_quit);
69 g_object_unref (menu_item_green); 68 g_object_unref (menu_item_red);
70 g_object_unref (menu_item_blue); 69 g_object_unref (menu_item_green);
71 g_object_unref (menu_item_fullscreen); 70 g_object_unref (menu_item_blue);
72 g_object_unref (menu_item_quit); 71 g_object_unref (menu_item_fullscreen);
73 72 g_object_unref (menu_item_quit);
74 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1)); 73
75 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2)); 74 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
76 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3)); 75 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
77 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu)); 76 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
78 77 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
79 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar)); 78
80 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE); 79 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
81 80 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
82 /* GtkCssProvider *provider = gtk_css_provider_new ();*/ 81
83 provider = gtk_css_provider_new (); 82 /* GtkCssProvider *provider = gtk_css_provider_new ();*/
84 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win)); 83 provider = gtk_css_provider_new ();
85 gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1); 84 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
86 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), 85 gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1);
87 GTK_STYLE_PROVIDER_PRIORITY_USER); 86 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
88 87 GTK_STYLE_PROVIDER_PRIORITY_USER);
89 /* gtk_widget_show (win);*/ 88
90 gtk_window_present (GTK_WINDOW (win)); 89 /* gtk_widget_show (win);*/
91 } 90 gtk_window_present (GTK_WINDOW (win));
92 91 }
93 int 92
94 main (int argc, char **argv) { 93 int
95 GtkApplication *app; 94 main (int argc, char **argv) {
96 int stat; 95 GtkApplication *app;
97 96 int stat;
98 app = gtk_application_new ("com.github.ToshioCP.menu2", G_APPLICATION_FLAGS_NONE); 97
99 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 98 app = gtk_application_new ("com.github.ToshioCP.menu2", G_APPLICATION_FLAGS_NONE);
100 99 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
101 stat =g_application_run (G_APPLICATION (app), argc, argv); 100
102 g_object_unref (app); 101 stat =g_application_run (G_APPLICATION (app), argc, argv);
103 return stat; 102 g_object_unref (app);
104 } 103 return stat;
105 104 }
105
~~~
- 5-26: Signal handlers. - 5-26: Signal handlers.
They have been explained in this section. They have been explained in this section.

View file

@ -1,4 +1,4 @@
Up: [Readme.md](../Readme.md), Prev: [Section 17](sec17.md) Up: [Readme.md](../Readme.md), Prev: [Section 17](sec17.md), Next: [Section 19](sec19.md)
# Ui file for menu and action entries # Ui file for menu and action entries
@ -13,22 +13,26 @@ The same goes for menus.
The ui file for menus has interface, menu tags. The ui file for menus has interface, menu tags.
The file starts and ends with interface tag. The file starts and ends with interface tag.
<interface> ~~~xml
<menu id="menubar"> <interface>
</menu> <menu id="menubar">
</interface> </menu>
</interface>
~~~
`menu` tag corresponds to GMenu object. `menu` tag corresponds to GMenu object.
`id` attribute defines the name of the object. `id` attribute defines the name of the object.
It will be refered by GtkBuilder. It will be refered by GtkBuilder.
<submenu> ~~~xml
<attribute name="label">File</attribute> <submenu>
<item> <attribute name="label">File</attribute>
<attribute name="label">New</attribute> <item>
<attribute name="action">win.new</attribute> <attribute name="label">New</attribute>
</item> <attribute name="action">win.new</attribute>
</submenu> </item>
</submenu>
~~~
`item` tag corresponds to item in GMenu which has the same structure as GMenuItem. `item` tag corresponds to item in GMenu which has the same structure as GMenuItem.
The item above has a label attribute. The item above has a label attribute.
@ -40,15 +44,17 @@ The GMenuItem has a link to GMenu.
The ui file above can be described as follows. The ui file above can be described as follows.
<item> ~~~xml
<attribute name="label">File</attribute> <item>
<link name="submenu"> <attribute name="label">File</attribute>
<item> <link name="submenu">
<attribute name="label">New</attribute> <item>
<attribute name="action">win.new</attribute> <attribute name="label">New</attribute>
</item> <attribute name="action">win.new</attribute>
</link> </item>
</item> </link>
</item>
~~~
`link` tag expresses the link to submenu. `link` tag expresses the link to submenu.
And at the same time it also expresses the submenu itself. And at the same time it also expresses the submenu itself.
@ -63,95 +69,101 @@ Its name is `menu3`.
The following is the ui file of the menu in `menu3`. The following is the ui file of the menu in `menu3`.
1 <?xml version="1.0" encoding="UTF-8"?> ~~~xml
2 <interface> 1 <?xml version="1.0" encoding="UTF-8"?>
3 <menu id="menubar"> 2 <interface>
4 <submenu> 3 <menu id="menubar">
5 <attribute name="label">File</attribute> 4 <submenu>
6 <section> 5 <attribute name="label">File</attribute>
7 <item> 6 <section>
8 <attribute name="label">New</attribute> 7 <item>
9 <attribute name="action">win.new</attribute> 8 <attribute name="label">New</attribute>
10 </item> 9 <attribute name="action">win.new</attribute>
11 <item> 10 </item>
12 <attribute name="label">Open</attribute> 11 <item>
13 <attribute name="action">win.open</attribute> 12 <attribute name="label">Open</attribute>
14 </item> 13 <attribute name="action">win.open</attribute>
15 </section> 14 </item>
16 <section> 15 </section>
17 <item> 16 <section>
18 <attribute name="label">Save</attribute> 17 <item>
19 <attribute name="action">win.save</attribute> 18 <attribute name="label">Save</attribute>
20 </item> 19 <attribute name="action">win.save</attribute>
21 <item> 20 </item>
22 <attribute name="label">Save As…</attribute> 21 <item>
23 <attribute name="action">win.saveas</attribute> 22 <attribute name="label">Save As…</attribute>
24 </item> 23 <attribute name="action">win.saveas</attribute>
25 </section> 24 </item>
26 <section> 25 </section>
27 <item> 26 <section>
28 <attribute name="label">Close</attribute> 27 <item>
29 <attribute name="action">win.close</attribute> 28 <attribute name="label">Close</attribute>
30 </item> 29 <attribute name="action">win.close</attribute>
31 </section> 30 </item>
32 <section> 31 </section>
33 <item> 32 <section>
34 <attribute name="label">Quit</attribute> 33 <item>
35 <attribute name="action">app.quit</attribute> 34 <attribute name="label">Quit</attribute>
36 </item> 35 <attribute name="action">app.quit</attribute>
37 </section> 36 </item>
38 </submenu> 37 </section>
39 <submenu> 38 </submenu>
40 <attribute name="label">Edit</attribute> 39 <submenu>
41 <section> 40 <attribute name="label">Edit</attribute>
42 <item> 41 <section>
43 <attribute name="label">Cut</attribute> 42 <item>
44 <attribute name="action">win.cut</attribute> 43 <attribute name="label">Cut</attribute>
45 </item> 44 <attribute name="action">win.cut</attribute>
46 <item> 45 </item>
47 <attribute name="label">Copy</attribute> 46 <item>
48 <attribute name="action">win.copy</attribute> 47 <attribute name="label">Copy</attribute>
49 </item> 48 <attribute name="action">win.copy</attribute>
50 <item> 49 </item>
51 <attribute name="label">Paste</attribute> 50 <item>
52 <attribute name="action">win.paste</attribute> 51 <attribute name="label">Paste</attribute>
53 </item> 52 <attribute name="action">win.paste</attribute>
54 </section> 53 </item>
55 <section> 54 </section>
56 <item> 55 <section>
57 <attribute name="label">Select All</attribute> 56 <item>
58 <attribute name="action">win.selectall</attribute> 57 <attribute name="label">Select All</attribute>
59 </item> 58 <attribute name="action">win.selectall</attribute>
60 </section> 59 </item>
61 </submenu> 60 </section>
62 <submenu> 61 </submenu>
63 <attribute name="label">View</attribute> 62 <submenu>
64 <section> 63 <attribute name="label">View</attribute>
65 <item> 64 <section>
66 <attribute name="label">Full Screen</attribute> 65 <item>
67 <attribute name="action">win.fullscreen</attribute> 66 <attribute name="label">Full Screen</attribute>
68 </item> 67 <attribute name="action">win.fullscreen</attribute>
69 </section> 68 </item>
70 </submenu> 69 </section>
71 </menu> 70 </submenu>
72 </interface> 71 </menu>
72 </interface>
~~~
The ui file is converted to the resource by the resouce compiler `glib-compile-resouces` with xml file below. The ui file is converted to the resource by the resouce compiler `glib-compile-resouces` with xml file below.
1 <?xml version="1.0" encoding="UTF-8"?> ~~~xml
2 <gresources> 1 <?xml version="1.0" encoding="UTF-8"?>
3 <gresource prefix="/com/github/ToshioCP/menu3"> 2 <gresources>
4 <file>menu3.ui</file> 3 <gresource prefix="/com/github/ToshioCP/menu3">
5 </gresource> 4 <file>menu3.ui</file>
6 </gresources> 5 </gresource>
6 </gresources>
~~~
GtkBuilder builds menus from the resource. GtkBuilder builds menus from the resource.
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui"); ~~~C
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")); GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
gtk_application_set_menubar (GTK_APPLICATION (app), menubar); gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
g_object_unref (builder); g_object_unref (builder);
~~~
It is important that `builder` is unreferred after the GMenuModel `menubar` is set to the application. It is important that `builder` is unreferred after the GMenuModel `menubar` is set to the application.
If you do it before setting, bad thing will happen -- your computer might freeze. If you do it before setting, bad thing will happen -- your computer might freeze.
@ -164,31 +176,42 @@ You can implement them easily with GActionEntry structure and `g_action_map_add_
GActionEntry contains action name, signal handlers, parameter and state. GActionEntry contains action name, signal handlers, parameter and state.
typedef struct _GActionEntry GActionEntry; ~~~C
typedef struct _GActionEntry GActionEntry;
struct _GActionEntry
{
const gchar *name; /* action name */
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data); /* activate handler */
const gchar *parameter_type; /* the type of the parameter given as a single GVariant type string */
const gchar *state; /* initial state given in GVariant text format */
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data); /* change-state handler */
/*< private >*/
gsize padding[3];
};
struct _GActionEntry
{
/* action name */
const gchar *name;
/* activate handler */
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
/* the type of the parameter given as a single GVariant type string */
const gchar *parameter_type;
/* initial state given in GVariant text format */
const gchar *state;
/* change-state handler */
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);
/*< private >*/
gsize padding[3];
};
~~~
For example, the actions in the previous section are: For example, the actions in the previous section are:
{ "fullscreen", NULL, NULL, "false", fullscreen_changed } ~~~C
{ "color", color_activated, "s", "red", NULL } { "fullscreen", NULL, NULL, "false", fullscreen_changed }
{ "quit", quit_activated, NULL, NULL, NULL }, { "color", color_activated, "s", "red", NULL }
{ "quit", quit_activated, NULL, NULL, NULL },
~~~
And `g_action_map_add_action_entries` does all the process instead of the functions you have needed. And `g_action_map_add_action_entries` does all the process instead of the functions you have needed.
const GActionEntry app_entries[] = { ~~~C
{ "quit", quit_activated, NULL, NULL, NULL } const GActionEntry app_entries[] = {
}; { "quit", quit_activated, NULL, NULL, NULL }
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app); };
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
G_N_ELEMENTS (app_entries), app);
~~~
The code above does: The code above does:
@ -198,12 +221,14 @@ The code above does:
The same goes for the other actions. The same goes for the other actions.
const GActionEntry win_entries[] = { ~~~C
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }, const GActionEntry win_entries[] = {
{ "color", color_activated, "s", "red", NULL } { "fullscreen", NULL, NULL, "false", fullscreen_changed },
}; { "color", color_activated, "s", "red", NULL }
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win); };
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,
G_N_ELEMENTS (win_entries), win);
~~~
The code above does: The code above does:
- Build a "fullscreen" action and "color" action. - Build a "fullscreen" action and "color" action.
@ -217,125 +242,129 @@ The code above does:
The C source code of `menu3` and `meson.build` is as follows. The C source code of `menu3` and `meson.build` is as follows.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 3 static void
5 } 4 new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
6 5 }
7 static void 6
8 open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 7 static void
9 } 8 open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
10 9 }
11 static void 10
12 save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 11 static void
13 } 12 save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
14 13 }
15 static void 14
16 saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 15 static void
17 } 16 saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
18 17 }
19 static void 18
20 close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 19 static void
21 } 20 close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
22 21 }
23 static void 22
24 cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 23 static void
25 } 24 cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
26 25 }
27 static void 26
28 copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 27 static void
29 } 28 copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
30 29 }
31 static void 30
32 paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 31 static void
33 } 32 paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
34 33 }
35 static void 34
36 selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) { 35 static void
37 } 36 selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
38 37 }
39 static void 38
40 fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) { 39 static void
41 if (g_variant_get_boolean (state)) 40 fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) {
42 gtk_window_maximize (GTK_WINDOW (win)); 41 if (g_variant_get_boolean (state))
43 else 42 gtk_window_maximize (GTK_WINDOW (win));
44 gtk_window_unmaximize (GTK_WINDOW (win)); 43 else
45 g_simple_action_set_state (action, state); 44 gtk_window_unmaximize (GTK_WINDOW (win));
46 } 45 g_simple_action_set_state (action, state);
47 46 }
48 static void 47
49 quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app) 48 static void
50 { 49 quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app)
51 g_application_quit (G_APPLICATION(app)); 50 {
52 } 51 g_application_quit (G_APPLICATION(app));
53 52 }
54 static void 53
55 on_activate (GApplication *app, gpointer user_data) { 54 static void
56 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app)); 55 on_activate (GApplication *app, gpointer user_data) {
57 56 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
58 const GActionEntry win_entries[] = { 57
59 { "new", new_activated, NULL, NULL, NULL }, 58 const GActionEntry win_entries[] = {
60 { "open", open_activated, NULL, NULL, NULL }, 59 { "new", new_activated, NULL, NULL, NULL },
61 { "save", save_activated, NULL, NULL, NULL }, 60 { "open", open_activated, NULL, NULL, NULL },
62 { "saveas", saveas_activated, NULL, NULL, NULL }, 61 { "save", save_activated, NULL, NULL, NULL },
63 { "close", close_activated, NULL, NULL, NULL }, 62 { "saveas", saveas_activated, NULL, NULL, NULL },
64 { "cut", cut_activated, NULL, NULL, NULL }, 63 { "close", close_activated, NULL, NULL, NULL },
65 { "copy", copy_activated, NULL, NULL, NULL }, 64 { "cut", cut_activated, NULL, NULL, NULL },
66 { "paste", paste_activated, NULL, NULL, NULL }, 65 { "copy", copy_activated, NULL, NULL, NULL },
67 { "selectall", selectall_activated, NULL, NULL, NULL }, 66 { "paste", paste_activated, NULL, NULL, NULL },
68 { "fullscreen", NULL, NULL, "false", fullscreen_changed } 67 { "selectall", selectall_activated, NULL, NULL, NULL },
69 }; 68 { "fullscreen", NULL, NULL, "false", fullscreen_changed }
70 g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win); 69 };
71 70 g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
72 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE); 71
73 72 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
74 gtk_window_set_title (GTK_WINDOW (win), "menu3"); 73
75 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 74 gtk_window_set_title (GTK_WINDOW (win), "menu3");
76 gtk_widget_show (win); 75 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
77 } 76 gtk_widget_show (win);
78 77 }
79 static void 78
80 on_startup (GApplication *app, gpointer user_data) { 79 static void
81 GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui"); 80 on_startup (GApplication *app, gpointer user_data) {
82 GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")); 81 GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
83 82 GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
84 gtk_application_set_menubar (GTK_APPLICATION (app), menubar); 83
85 g_object_unref (builder); 84 gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
86 85 g_object_unref (builder);
87 const GActionEntry app_entries[] = { 86
88 { "quit", quit_activated, NULL, NULL, NULL } 87 const GActionEntry app_entries[] = {
89 }; 88 { "quit", quit_activated, NULL, NULL, NULL }
90 g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app); 89 };
91 } 90 g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
92 91 }
93 int 92
94 main (int argc, char **argv) { 93 int
95 GtkApplication *app; 94 main (int argc, char **argv) {
96 int stat; 95 GtkApplication *app;
97 96 int stat;
98 app = gtk_application_new ("com.github.ToshioCP.menu3", G_APPLICATION_FLAGS_NONE); 97
99 g_signal_connect (app, "startup", G_CALLBACK (on_startup), NULL); 98 app = gtk_application_new ("com.github.ToshioCP.menu3", G_APPLICATION_FLAGS_NONE);
100 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 99 g_signal_connect (app, "startup", G_CALLBACK (on_startup), NULL);
101 100 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
102 stat =g_application_run (G_APPLICATION (app), argc, argv); 101
103 g_object_unref (app); 102 stat =g_application_run (G_APPLICATION (app), argc, argv);
104 return stat; 103 g_object_unref (app);
105 } 104 return stat;
106 105 }
106
~~~
meson.build meson.build
1 project('menu3', 'c') ~~~meson
2 1 project('menu3', 'c')
3 gtkdep = dependency('gtk4') 2
4 3 gtkdep = dependency('gtk4')
5 gnome=import('gnome') 4
6 resources = gnome.compile_resources('resources','menu3.gresource.xml') 5 gnome=import('gnome')
7 6 resources = gnome.compile_resources('resources','menu3.gresource.xml')
8 sourcefiles=files('menu3.c') 7
9 8 sourcefiles=files('menu3.c')
10 executable('menu3', sourcefiles, resources, dependencies: gtkdep) 9
10 executable('menu3', sourcefiles, resources, dependencies: gtkdep)
~~~
Up: [Readme.md](../Readme.md), Prev: [Section 17](sec17.md) Up: [Readme.md](../Readme.md), Prev: [Section 17](sec17.md), Next: [Section 19](sec19.md)

View file

@ -1,4 +1,4 @@
Up: [Readme.md](../Readme.md), Prev: [Section 18](sec18.md) Up: [Readme.md](../Readme.md), Prev: [Section 18](sec18.md), Next: [Section 20](sec20.md)
# GtkDrawingArea and Cairo # GtkDrawingArea and Cairo
@ -46,37 +46,39 @@ This will be a destnation.
Here's a simple example code that draws a small square and save it as a png file. Here's a simple example code that draws a small square and save it as a png file.
1 #include <cairo.h> ~~~C
2 1 #include <cairo.h>
3 int 2
4 main (int argc, char **argv) 3 int
5 { 4 main (int argc, char **argv)
6 cairo_surface_t *surface; 5 {
7 cairo_t *cr; 6 cairo_surface_t *surface;
8 int width = 100; 7 cairo_t *cr;
9 int height = 100; 8 int width = 100;
10 9 int height = 100;
11 /* Generate surface and cairo */ 10
12 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); 11 /* Generate surface and cairo */
13 cr = cairo_create (surface); 12 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
14 13 cr = cairo_create (surface);
15 /* Drawing starts here. */ 14
16 /* Paint the background white */ 15 /* Drawing starts here. */
17 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); 16 /* Paint the background white */
18 cairo_paint (cr); 17 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
19 /* Draw a black rectangle */ 18 cairo_paint (cr);
20 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); 19 /* Draw a black rectangle */
21 cairo_set_line_width (cr, 2.0); 20 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
22 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0); 21 cairo_set_line_width (cr, 2.0);
23 cairo_stroke (cr); 22 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0);
24 23 cairo_stroke (cr);
25 /* Write the surface to a png file and clean up cairo and surface. */ 24
26 cairo_surface_write_to_png (surface, "rectangle.png"); 25 /* Write the surface to a png file and clean up cairo and surface. */
27 cairo_destroy (cr); 26 cairo_surface_write_to_png (surface, "rectangle.png");
28 cairo_surface_destroy (surface); 27 cairo_destroy (cr);
29 28 cairo_surface_destroy (surface);
30 return 0; 29
31 } 30 return 0;
31 }
~~~
- 1: Include the header file of cairo. - 1: Include the header file of cairo.
- 12: `cairo_image_surface_create` creates an image surface. - 12: `cairo_image_surface_create` creates an image surface.
@ -117,45 +119,47 @@ If you aren't familiar with cairo, it is strongly recommended to read the [tutor
The following is a very simple example. The following is a very simple example.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) { 3 static void
5 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* whilte */ 4 draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) {
6 cairo_paint (cr); 5 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* whilte */
7 cairo_set_line_width (cr, 2.0); 6 cairo_paint (cr);
8 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ 7 cairo_set_line_width (cr, 2.0);
9 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0); 8 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
10 cairo_stroke (cr); 9 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0);
11 } 10 cairo_stroke (cr);
12 11 }
13 static void 12
14 on_activate (GApplication *app, gpointer user_data) { 13 static void
15 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app)); 14 on_activate (GApplication *app, gpointer user_data) {
16 GtkWidget *area = gtk_drawing_area_new (); 15 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
17 16 GtkWidget *area = gtk_drawing_area_new ();
18 gtk_window_set_title (GTK_WINDOW (win), "da1"); 17
19 /* Set initial size of width and height */ 18 gtk_window_set_title (GTK_WINDOW (win), "da1");
20 gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 100); 19 /* Set initial size of width and height */
21 gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 100); 20 gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 100);
22 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL); 21 gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 100);
23 gtk_window_set_child (GTK_WINDOW (win), area); 22 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
24 23 gtk_window_set_child (GTK_WINDOW (win), area);
25 gtk_widget_show (win); 24
26 } 25 gtk_widget_show (win);
27 26 }
28 int 27
29 main (int argc, char **argv) { 28 int
30 GtkApplication *app; 29 main (int argc, char **argv) {
31 int stat; 30 GtkApplication *app;
32 31 int stat;
33 app = gtk_application_new ("com.github.ToshioCP.da1", G_APPLICATION_FLAGS_NONE); 32
34 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 33 app = gtk_application_new ("com.github.ToshioCP.da1", G_APPLICATION_FLAGS_NONE);
35 stat =g_application_run (G_APPLICATION (app), argc, argv); 34 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
36 g_object_unref (app); 35 stat =g_application_run (G_APPLICATION (app), argc, argv);
37 return stat; 36 g_object_unref (app);
38 } 37 return stat;
39 38 }
39
~~~
The function `main` is almost same as before. The function `main` is almost same as before.
The two functions `on_activate` and `draw_function` is important in this example. The two functions `on_activate` and `draw_function` is important in this example.
@ -194,4 +198,4 @@ The square always appears at the center of the window because the drawing functi
![Square in the window](../image/da1.png) ![Square in the window](../image/da1.png)
Up: [Readme.md](../Readme.md), Prev: [Section 18](sec18.md) Up: [Readme.md](../Readme.md), Prev: [Section 18](sec18.md), Next: [Section 20](sec20.md)

View file

@ -143,7 +143,8 @@ Modify `env.sh`.
# compiler # compiler
CPPFLAGS="-I$HOME/local/include" CPPFLAGS="-I$HOME/local/include"
LDFLAGS="-L$HOME/local/lib" LDFLAGS="-L$HOME/local/lib"
PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig:$HOME/local/lib/x86_64-linux-gnu/pkgconfig:$HOME/local/share/pkgconfig" PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig:$HOME/local/lib/x86_64-linux-gnu/pkgconfig:
$HOME/local/share/pkgconfig"
export CPPFLAGS LDFLAGS PKG_CONFIG_PATH export CPPFLAGS LDFLAGS PKG_CONFIG_PATH
# linker # linker
LD_LIBRARY_PATH="$HOME/local/lib/x86_64-linux-gnu/" LD_LIBRARY_PATH="$HOME/local/lib/x86_64-linux-gnu/"

View file

@ -34,87 +34,89 @@ The image in the previous subsection gives us the structure of the widgets.
Title bar, four buttons in the tool bar and two widgets textview and drawing area. Title bar, four buttons in the tool bar and two widgets textview and drawing area.
The ui file is as follows. The ui file is as follows.
1 <interface> ~~~xml
2 <object class="GtkApplicationWindow" id="win"> 1 <interface>
3 <property name="title">color changer</property> 2 <object class="GtkApplicationWindow" id="win">
4 <property name="default-width">600</property> 3 <property name="title">color changer</property>
5 <property name="default-height">400</property> 4 <property name="default-width">600</property>
6 <child> 5 <property name="default-height">400</property>
7 <object class="GtkBox" id="boxv"> 6 <child>
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property> 7 <object class="GtkBox" id="boxv">
9 <child> 8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
10 <object class="GtkBox" id="boxh1"> 9 <child>
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> 10 <object class="GtkBox" id="boxh1">
12 <child> 11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
13 <object class="GtkLabel" id="dmy1"> 12 <child>
14 <property name="width-chars">10</property> 13 <object class="GtkLabel" id="dmy1">
15 </object> 14 <property name="width-chars">10</property>
16 </child> 15 </object>
17 <child> 16 </child>
18 <object class="GtkButton" id="btnr"> 17 <child>
19 <property name="label">Run</property> 18 <object class="GtkButton" id="btnr">
20 <signal name="clicked" handler="run_cb"></signal> 19 <property name="label">Run</property>
21 20 <signal name="clicked" handler="run_cb"></signal>
22 </object> 21
23 </child> 22 </object>
24 <child> 23 </child>
25 <object class="GtkButton" id="btno"> 24 <child>
26 <property name="label">Open</property> 25 <object class="GtkButton" id="btno">
27 <signal name="clicked" handler="open_cb"></signal> 26 <property name="label">Open</property>
28 </object> 27 <signal name="clicked" handler="open_cb"></signal>
29 </child> 28 </object>
30 <child> 29 </child>
31 <object class="GtkLabel" id="dmy2"> 30 <child>
32 <property name="hexpand">TRUE</property> 31 <object class="GtkLabel" id="dmy2">
33 </object> 32 <property name="hexpand">TRUE</property>
34 </child> 33 </object>
35 <child> 34 </child>
36 <object class="GtkButton" id="btns"> 35 <child>
37 <property name="label">Save</property> 36 <object class="GtkButton" id="btns">
38 <signal name="clicked" handler="save_cb"></signal> 37 <property name="label">Save</property>
39 </object> 38 <signal name="clicked" handler="save_cb"></signal>
40 </child> 39 </object>
41 <child> 40 </child>
42 <object class="GtkButton" id="btnc"> 41 <child>
43 <property name="label">Close</property> 42 <object class="GtkButton" id="btnc">
44 <signal name="clicked" handler="close_cb"></signal> 43 <property name="label">Close</property>
45 </object> 44 <signal name="clicked" handler="close_cb"></signal>
46 </child> 45 </object>
47 <child> 46 </child>
48 <object class="GtkLabel" id="dmy3"> 47 <child>
49 <property name="width-chars">10</property> 48 <object class="GtkLabel" id="dmy3">
50 </object> 49 <property name="width-chars">10</property>
51 </child> 50 </object>
52 </object> 51 </child>
53 </child> 52 </object>
54 <child> 53 </child>
55 <object class="GtkBox" id="boxh2"> 54 <child>
56 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> 55 <object class="GtkBox" id="boxh2">
57 <property name="homogeneous">TRUE</property> 56 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
58 <child> 57 <property name="homogeneous">TRUE</property>
59 <object class="GtkScrolledWindow" id="scr"> 58 <child>
60 <property name="hexpand">TRUE</property> 59 <object class="GtkScrolledWindow" id="scr">
61 <property name="vexpand">TRUE</property> 60 <property name="hexpand">TRUE</property>
62 <child> 61 <property name="vexpand">TRUE</property>
63 <object class="TfeTextView" id="tv"> 62 <child>
64 <property name="wrap-mode">GTK_WRAP_WORD_CHAR</property> 63 <object class="TfeTextView" id="tv">
65 </object> 64 <property name="wrap-mode">GTK_WRAP_WORD_CHAR</property>
66 </child> 65 </object>
67 </object> 66 </child>
68 </child> 67 </object>
69 <child> 68 </child>
70 <object class="GtkDrawingArea" id="da"> 69 <child>
71 <property name="hexpand">TRUE</property> 70 <object class="GtkDrawingArea" id="da">
72 <property name="vexpand">TRUE</property> 71 <property name="hexpand">TRUE</property>
73 </object> 72 <property name="vexpand">TRUE</property>
74 </child> 73 </object>
75 </object> 74 </child>
76 </child> 75 </object>
77 </object> 76 </child>
78 </child> 77 </object>
79 </object> 78 </child>
80 </interface> 79 </object>
81 80 </interface>
81
~~~
- 9-53: This part describes the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`. - 9-53: This part describes the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
This is similar to the toolbar of tfe text editor in [Section 8](sec8.md). This is similar to the toolbar of tfe text editor in [Section 8](sec8.md).
@ -132,12 +134,14 @@ TfeTextView is a child of GtkScrolledWindow.
The xml file for the resource compiler is almost same as before. The xml file for the resource compiler is almost same as before.
Just substitute "color" for "tfe". Just substitute "color" for "tfe".
1 <?xml version="1.0" encoding="UTF-8"?> ~~~xml
2 <gresources> 1 <?xml version="1.0" encoding="UTF-8"?>
3 <gresource prefix="/com/github/ToshioCP/color"> 2 <gresources>
4 <file>color.ui</file> 3 <gresource prefix="/com/github/ToshioCP/color">
5 </gresource> 4 <file>color.ui</file>
6 </gresources> 5 </gresource>
6 </gresources>
~~~
# Tfetextview.h, tfetextview.c and color.h # Tfetextview.h, tfetextview.c and color.h
@ -152,9 +156,11 @@ The only difference is the header file in tfettextview.c.
Color.h just includes tfetextview.h. Color.h just includes tfetextview.h.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 #include "tfetextview.h" 2
3 #include "tfetextview.h"
~~~
# Colorapplication.c # Colorapplication.c
@ -169,128 +175,130 @@ Particularly, `Run` signal handler is the point in this program.
The following is `colorapplication.c`. The following is `colorapplication.c`.
1 #include "color.h" ~~~C
2 1 #include "color.h"
3 static GtkWidget *win; 2
4 static GtkWidget *tv; 3 static GtkWidget *win;
5 static GtkWidget *da; 4 static GtkWidget *tv;
6 5 static GtkWidget *da;
7 static cairo_surface_t *surface = NULL; 6
8 7 static cairo_surface_t *surface = NULL;
9 static void 8
10 run (void) { 9 static void
11 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 10 run (void) {
12 GtkTextIter start_iter; 11 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
13 GtkTextIter end_iter; 12 GtkTextIter start_iter;
14 char *contents; 13 GtkTextIter end_iter;
15 cairo_t *cr; 14 char *contents;
16 15 cairo_t *cr;
17 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter); 16
18 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE); 17 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
19 if (surface) { 18 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
20 cr = cairo_create (surface); 19 if (surface) {
21 if (g_strcmp0 ("red", contents) == 0) 20 cr = cairo_create (surface);
22 cairo_set_source_rgb (cr, 1, 0, 0); 21 if (g_strcmp0 ("red", contents) == 0)
23 else if (g_strcmp0 ("green", contents) == 0) 22 cairo_set_source_rgb (cr, 1, 0, 0);
24 cairo_set_source_rgb (cr, 0, 1, 0); 23 else if (g_strcmp0 ("green", contents) == 0)
25 else if (g_strcmp0 ("blue", contents) == 0) 24 cairo_set_source_rgb (cr, 0, 1, 0);
26 cairo_set_source_rgb (cr, 0, 0, 1); 25 else if (g_strcmp0 ("blue", contents) == 0)
27 else if (g_strcmp0 ("white", contents) == 0) 26 cairo_set_source_rgb (cr, 0, 0, 1);
28 cairo_set_source_rgb (cr, 1, 1, 1); 27 else if (g_strcmp0 ("white", contents) == 0)
29 else if (g_strcmp0 ("black", contents) == 0) 28 cairo_set_source_rgb (cr, 1, 1, 1);
30 cairo_set_source_rgb (cr, 0, 0, 0); 29 else if (g_strcmp0 ("black", contents) == 0)
31 else if (g_strcmp0 ("light", contents) == 0) 30 cairo_set_source_rgb (cr, 0, 0, 0);
32 cairo_set_source_rgba (cr, 1, 1, 1, 0.5); 31 else if (g_strcmp0 ("light", contents) == 0)
33 else if (g_strcmp0 ("dark", contents) == 0) 32 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
34 cairo_set_source_rgba (cr, 0, 0, 0, 0.5); 33 else if (g_strcmp0 ("dark", contents) == 0)
35 else 34 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
36 cairo_set_source_surface (cr, surface, 0, 0); 35 else
37 cairo_paint (cr); 36 cairo_set_source_surface (cr, surface, 0, 0);
38 cairo_destroy (cr); 37 cairo_paint (cr);
39 } 38 cairo_destroy (cr);
40 } 39 }
41 40 }
42 void 41
43 run_cb (GtkWidget *btnr) { 42 void
44 run (); 43 run_cb (GtkWidget *btnr) {
45 gtk_widget_queue_draw (GTK_WIDGET (da)); 44 run ();
46 } 45 gtk_widget_queue_draw (GTK_WIDGET (da));
47 46 }
48 void 47
49 open_cb (GtkWidget *btno) { 48 void
50 tfe_text_view_open (TFE_TEXT_VIEW (tv), win); 49 open_cb (GtkWidget *btno) {
51 } 50 tfe_text_view_open (TFE_TEXT_VIEW (tv), win);
52 51 }
53 void 52
54 save_cb (GtkWidget *btns) { 53 void
55 tfe_text_view_save (TFE_TEXT_VIEW (tv)); 54 save_cb (GtkWidget *btns) {
56 } 55 tfe_text_view_save (TFE_TEXT_VIEW (tv));
57 56 }
58 void 57
59 close_cb (GtkWidget *btnc) { 58 void
60 if (surface) 59 close_cb (GtkWidget *btnc) {
61 cairo_surface_destroy (surface); 60 if (surface)
62 gtk_window_destroy (GTK_WINDOW (win)); 61 cairo_surface_destroy (surface);
63 } 62 gtk_window_destroy (GTK_WINDOW (win));
64 63 }
65 static void 64
66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) { 65 static void
67 if (surface) 66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
68 cairo_surface_destroy (surface); 67 if (surface)
69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); 68 cairo_surface_destroy (surface);
70 run (); 69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
71 } 70 run ();
72 71 }
73 static void 72
74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) { 73 static void
75 if (surface) { 74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
76 cairo_set_source_surface (cr, surface, 0, 0); 75 if (surface) {
77 cairo_paint (cr); 76 cairo_set_source_surface (cr, surface, 0, 0);
78 } 77 cairo_paint (cr);
79 } 78 }
80 79 }
81 static void 80
82 activate (GApplication *application) { 81 static void
83 gtk_widget_show (win); 82 activate (GApplication *application) {
84 } 83 gtk_widget_show (win);
85 84 }
86 static void 85
87 startup (GApplication *application) { 86 static void
88 GtkApplication *app = GTK_APPLICATION (application); 87 startup (GApplication *application) {
89 GtkBuilder *build; 88 GtkApplication *app = GTK_APPLICATION (application);
90 89 GtkBuilder *build;
91 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui"); 90
92 win = GTK_WIDGET (gtk_builder_get_object (build, "win")); 91 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
93 gtk_window_set_application (GTK_WINDOW (win), app); 92 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
94 tv = GTK_WIDGET (gtk_builder_get_object (build, "tv")); 93 gtk_window_set_application (GTK_WINDOW (win), app);
95 da = GTK_WIDGET (gtk_builder_get_object (build, "da")); 94 tv = GTK_WIDGET (gtk_builder_get_object (build, "tv"));
96 g_object_unref(build); 95 da = GTK_WIDGET (gtk_builder_get_object (build, "da"));
97 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL); 96 g_object_unref(build);
98 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL); 97 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
99 98 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
100 GdkDisplay *display; 99
101 100 GdkDisplay *display;
102 display = gtk_widget_get_display (GTK_WIDGET (win)); 101
103 GtkCssProvider *provider = gtk_css_provider_new (); 102 display = gtk_widget_get_display (GTK_WIDGET (win));
104 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1); 103 GtkCssProvider *provider = gtk_css_provider_new ();
105 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER); 104 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
106 } 105 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
107 106 }
108 int 107
109 main (int argc, char **argv) { 108 int
110 GtkApplication *app; 109 main (int argc, char **argv) {
111 int stat; 110 GtkApplication *app;
112 111 int stat;
113 app = gtk_application_new ("com.github.ToshioCP.color", G_APPLICATION_FLAGS_NONE); 112
114 113 app = gtk_application_new ("com.github.ToshioCP.color", G_APPLICATION_FLAGS_NONE);
115 g_signal_connect (app, "startup", G_CALLBACK (startup), NULL); 114
116 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); 115 g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
117 116 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
118 stat =g_application_run (G_APPLICATION (app), argc, argv); 117
119 g_object_unref (app); 118 stat =g_application_run (G_APPLICATION (app), argc, argv);
120 return stat; 119 g_object_unref (app);
121 } 120 return stat;
122 121 }
122
~~~
- 108-121: The function `main` is almost same as before but there are some differences. - 108-121: The function `main` is almost same as before but there are some differences.
The application ID is "com.github.ToshioCP.color". The application ID is "com.github.ToshioCP.color".
@ -332,16 +340,18 @@ Alpha channel is used.
This file is almost same as before. This file is almost same as before.
An argument "export_dynamic: true" is added to executable function. An argument "export_dynamic: true" is added to executable function.
1 project('color', 'c') ~~~meson
2 1 project('color', 'c')
3 gtkdep = dependency('gtk4') 2
4 3 gtkdep = dependency('gtk4')
5 gnome=import('gnome') 4
6 resources = gnome.compile_resources('resources','color.gresource.xml') 5 gnome=import('gnome')
7 6 resources = gnome.compile_resources('resources','color.gresource.xml')
8 sourcefiles=files('colorapplication.c', 'tfetextview.c') 7
9 8 sourcefiles=files('colorapplication.c', 'tfetextview.c')
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true) 9
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
~~~
# Compile and execute it # Compile and execute it

View file

@ -20,19 +20,21 @@ That's all.
Very simple. Very simple.
The following is the C code representing the scenario above. The following is the C code representing the scenario above.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 int 2
4 main (int argc, char **argv) { 3 int
5 GtkApplication *app; 4 main (int argc, char **argv) {
6 int stat; 5 GtkApplication *app;
7 6 int stat;
8 app = gtk_application_new ("com.github.ToshioCP.pr1", G_APPLICATION_FLAGS_NONE); 7
9 stat =g_application_run (G_APPLICATION (app), argc, argv); 8 app = gtk_application_new ("com.github.ToshioCP.pr1", G_APPLICATION_FLAGS_NONE);
10 g_object_unref (app); 9 stat =g_application_run (G_APPLICATION (app), argc, argv);
11 return stat; 10 g_object_unref (app);
12 } 11 return stat;
13 12 }
13
~~~
The first line says that this program includes the header files of the Gtk libraries. The first line says that this program includes the header files of the Gtk libraries.
The function `main` above is a startup function in C language. The function `main` above is a startup function in C language.
@ -54,7 +56,9 @@ Let's run it.
$ ./a.out $ ./a.out
(a.out:13533): GLib-GIO-WARNING **: 15:30:17.449: Your application does not implement g_application_activate() and has no handlers connected to the "activate" signal. It should do one of these. (a.out:13533): GLib-GIO-WARNING **: 15:30:17.449: Your application does not implement
g_application_activate() and has no handlers connected to the "activate" signal.
It should do one of these.
$ $
Oh, just an error message. Oh, just an error message.
@ -97,25 +101,27 @@ Now we can solve the problem in `pr1.c`.
We need to connect the activate signal to a handler. We need to connect the activate signal to a handler.
We use a function `g_signal_connect` which connects a signal to a handler. We use a function `g_signal_connect` which connects a signal to a handler.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 on_activate (GApplication *app, gpointer *user_data) { 3 static void
5 g_print ("GtkApplication is activated.\n"); 4 on_activate (GApplication *app, gpointer *user_data) {
6 } 5 g_print ("GtkApplication is activated.\n");
7 6 }
8 int 7
9 main (int argc, char **argv) { 8 int
10 GtkApplication *app; 9 main (int argc, char **argv) {
11 int stat; 10 GtkApplication *app;
12 11 int stat;
13 app = gtk_application_new ("com.github.ToshioCP.pr2", G_APPLICATION_FLAGS_NONE); 12
14 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 13 app = gtk_application_new ("com.github.ToshioCP.pr2", G_APPLICATION_FLAGS_NONE);
15 stat =g_application_run (G_APPLICATION (app), argc, argv); 14 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
16 g_object_unref (app); 15 stat =g_application_run (G_APPLICATION (app), argc, argv);
17 return stat; 16 g_object_unref (app);
18 } 17 return stat;
19 18 }
19
~~~
First, we define the handler `on_activate` which simply displays a message. First, we define the handler `on_activate` which simply displays a message.
In the function `main`, we add `g_signal_connect` before `g_application_run`. In the function `main`, we add `g_signal_connect` before `g_application_run`.
@ -185,14 +191,16 @@ Now rewrite the function `on_activate`.
#### Generate a GtkWindow #### Generate a GtkWindow
1 static void ~~~C
2 on_activate (GApplication *app, gpointer user_data) { 1 static void
3 GtkWidget *win; 2 on_activate (GApplication *app, gpointer user_data) {
4 3 GtkWidget *win;
5 win = gtk_window_new (); 4
6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app)); 5 win = gtk_window_new ();
7 gtk_widget_show (win); 6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
8 } 7 gtk_widget_show (win);
8 }
~~~
Widget is an abstract concept that includes all the GUI interfaces such as windows, dialogs, buttons, multiline text, containers and so on. Widget is an abstract concept that includes all the GUI interfaces such as windows, dialogs, buttons, multiline text, containers and so on.
And GtkWidget is a base object from which all the GUI objects derive. And GtkWidget is a base object from which all the GUI objects derive.
@ -265,15 +273,17 @@ It is recommended to use it instead of GtkWindow when you use GtkApplication.
Now rewrite the program and use GtkAppliction Window. Now rewrite the program and use GtkAppliction Window.
1 static void ~~~C
2 on_activate (GApplication *app, gpointer user_data) { 1 static void
3 GtkWidget *win; 2 on_activate (GApplication *app, gpointer user_data) {
4 3 GtkWidget *win;
5 win = gtk_application_window_new (GTK_APPLICATION (app)); 4
6 gtk_window_set_title (GTK_WINDOW (win), "pr4"); 5 win = gtk_application_window_new (GTK_APPLICATION (app));
7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 6 gtk_window_set_title (GTK_WINDOW (win), "pr4");
8 gtk_widget_show (win); 7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
9 } 8 gtk_widget_show (win);
9 }
~~~
When you generate GtkApplicationWindow, you need to give GtkApplication object as an argument. When you generate GtkApplicationWindow, you need to give GtkApplication object as an argument.
Then it automatically connect these two objects. Then it automatically connect these two objects.

View file

@ -11,35 +11,37 @@ Now we go on to the next topic, widgets in the window.
The simplest widget is GtkLabel. The simplest widget is GtkLabel.
It is a widget with a string in it. It is a widget with a string in it.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 on_activate (GApplication *app, gpointer user_data) { 3 static void
5 GtkWidget *win; 4 on_activate (GApplication *app, gpointer user_data) {
6 GtkWidget *lab; 5 GtkWidget *win;
7 6 GtkWidget *lab;
8 win = gtk_application_window_new (GTK_APPLICATION (app)); 7
9 gtk_window_set_title (GTK_WINDOW (win), "lb1"); 8 win = gtk_application_window_new (GTK_APPLICATION (app));
10 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 9 gtk_window_set_title (GTK_WINDOW (win), "lb1");
11 10 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
12 lab = gtk_label_new ("Hello."); 11
13 gtk_window_set_child (GTK_WINDOW (win), lab); 12 lab = gtk_label_new ("Hello.");
14 13 gtk_window_set_child (GTK_WINDOW (win), lab);
15 gtk_widget_show (win); 14
16 } 15 gtk_widget_show (win);
17 16 }
18 int 17
19 main (int argc, char **argv) { 18 int
20 GtkApplication *app; 19 main (int argc, char **argv) {
21 int stat; 20 GtkApplication *app;
22 21 int stat;
23 app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_FLAGS_NONE); 22
24 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 23 app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_FLAGS_NONE);
25 stat =g_application_run (G_APPLICATION (app), argc, argv); 24 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
26 g_object_unref (app); 25 stat =g_application_run (G_APPLICATION (app), argc, argv);
27 return stat; 26 g_object_unref (app);
28 } 27 return stat;
29 28 }
29
~~~
Save this program to a file `lb1.c`. Save this program to a file `lb1.c`.
Then compile and run it. Then compile and run it.
@ -100,41 +102,43 @@ In this subsection, we will make a button with a label.
When a button is clicked on, it emits a "clicked" signal. When a button is clicked on, it emits a "clicked" signal.
The following program shows how to catch the signal and do something. The following program shows how to catch the signal and do something.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 click_cb (GtkButton *btn, gpointer user_data) { 3 static void
5 g_print ("Clicked.\n"); 4 click_cb (GtkButton *btn, gpointer user_data) {
6 } 5 g_print ("Clicked.\n");
7 6 }
8 static void 7
9 on_activate (GApplication *app, gpointer user_data) { 8 static void
10 GtkWidget *win; 9 on_activate (GApplication *app, gpointer user_data) {
11 GtkWidget *btn; 10 GtkWidget *win;
12 11 GtkWidget *btn;
13 win = gtk_application_window_new (GTK_APPLICATION (app)); 12
14 gtk_window_set_title (GTK_WINDOW (win), "lb2"); 13 win = gtk_application_window_new (GTK_APPLICATION (app));
15 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 14 gtk_window_set_title (GTK_WINDOW (win), "lb2");
16 15 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
17 btn = gtk_button_new_with_label ("Click me"); 16
18 gtk_window_set_child (GTK_WINDOW (win), btn); 17 btn = gtk_button_new_with_label ("Click me");
19 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL); 18 gtk_window_set_child (GTK_WINDOW (win), btn);
20 19 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
21 gtk_widget_show (win); 20
22 } 21 gtk_widget_show (win);
23 22 }
24 int 23
25 main (int argc, char **argv) { 24 int
26 GtkApplication *app; 25 main (int argc, char **argv) {
27 int stat; 26 GtkApplication *app;
28 27 int stat;
29 app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_FLAGS_NONE); 28
30 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 29 app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_FLAGS_NONE);
31 stat =g_application_run (G_APPLICATION (app), argc, argv); 30 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
32 g_object_unref (app); 31 stat =g_application_run (G_APPLICATION (app), argc, argv);
33 return stat; 32 g_object_unref (app);
34 } 33 return stat;
35 34 }
35
~~~
Look at the line 17 to 19. Look at the line 17 to 19.
First, generate a GtkButton widget `btn` with a label "Click me". First, generate a GtkButton widget `btn` with a label "Click me".
@ -157,27 +161,29 @@ However, using g_print is out of harmony with GTK which is a GUI library.
So, we will change the handler. So, we will change the handler.
The following code is `lb3.c`. The following code is `lb3.c`.
1 static void ~~~C
2 click_cb (GtkButton *btn, gpointer user_data) { 1 static void
3 GtkWindow *win = GTK_WINDOW (user_data); 2 click_cb (GtkButton *btn, gpointer user_data) {
4 gtk_window_destroy (win); 3 GtkWindow *win = GTK_WINDOW (user_data);
5 } 4 gtk_window_destroy (win);
6 5 }
7 static void 6
8 on_activate (GApplication *app, gpointer user_data) { 7 static void
9 GtkWidget *win; 8 on_activate (GApplication *app, gpointer user_data) {
10 GtkWidget *btn; 9 GtkWidget *win;
11 10 GtkWidget *btn;
12 win = gtk_application_window_new (GTK_APPLICATION (app)); 11
13 gtk_window_set_title (GTK_WINDOW (win), "lb3"); 12 win = gtk_application_window_new (GTK_APPLICATION (app));
14 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 13 gtk_window_set_title (GTK_WINDOW (win), "lb3");
15 14 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
16 btn = gtk_button_new_with_label ("Quit"); 15
17 gtk_window_set_child (GTK_WINDOW (win), btn); 16 btn = gtk_button_new_with_label ("Quit");
18 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win); 17 gtk_window_set_child (GTK_WINDOW (win), btn);
19 18 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
20 gtk_widget_show (win); 19
21 } 20 gtk_widget_show (win);
21 }
~~~
And the difference between `lb2.c` and `lb3.c` is as follows. And the difference between `lb2.c` and `lb3.c` is as follows.
@ -237,63 +243,65 @@ After this, the Widgets are connected as following diagram.
Now, code it. Now, code it.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 click1_cb (GtkButton *btn, gpointer user_data) { 3 static void
5 const gchar *s; 4 click1_cb (GtkButton *btn, gpointer user_data) {
6 5 const gchar *s;
7 s = gtk_button_get_label (btn); 6
8 if (g_strcmp0 (s, "Hello.") == 0) 7 s = gtk_button_get_label (btn);
9 gtk_button_set_label (btn, "Good-bye."); 8 if (g_strcmp0 (s, "Hello.") == 0)
10 else 9 gtk_button_set_label (btn, "Good-bye.");
11 gtk_button_set_label (btn, "Hello."); 10 else
12 } 11 gtk_button_set_label (btn, "Hello.");
13 12 }
14 static void 13
15 click2_cb (GtkButton *btn, gpointer user_data) { 14 static void
16 GtkWindow *win = GTK_WINDOW (user_data); 15 click2_cb (GtkButton *btn, gpointer user_data) {
17 gtk_window_destroy (win); 16 GtkWindow *win = GTK_WINDOW (user_data);
18 } 17 gtk_window_destroy (win);
19 18 }
20 static void 19
21 on_activate (GApplication *app, gpointer user_data) { 20 static void
22 GtkWidget *win; 21 on_activate (GApplication *app, gpointer user_data) {
23 GtkWidget *box; 22 GtkWidget *win;
24 GtkWidget *btn1; 23 GtkWidget *box;
25 GtkWidget *btn2; 24 GtkWidget *btn1;
26 25 GtkWidget *btn2;
27 win = gtk_application_window_new (GTK_APPLICATION (app)); 26
28 gtk_window_set_title (GTK_WINDOW (win), "lb4"); 27 win = gtk_application_window_new (GTK_APPLICATION (app));
29 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 28 gtk_window_set_title (GTK_WINDOW (win), "lb4");
30 29 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
31 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); 30
32 gtk_box_set_homogeneous (GTK_BOX (box), TRUE); 31 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
33 gtk_window_set_child (GTK_WINDOW (win), box); 32 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
34 33 gtk_window_set_child (GTK_WINDOW (win), box);
35 btn1 = gtk_button_new_with_label ("Hello."); 34
36 g_signal_connect (btn1, "clicked", G_CALLBACK (click1_cb), NULL); 35 btn1 = gtk_button_new_with_label ("Hello.");
37 36 g_signal_connect (btn1, "clicked", G_CALLBACK (click1_cb), NULL);
38 btn2 = gtk_button_new_with_label ("Quit"); 37
39 g_signal_connect (btn2, "clicked", G_CALLBACK (click2_cb), win); 38 btn2 = gtk_button_new_with_label ("Quit");
40 39 g_signal_connect (btn2, "clicked", G_CALLBACK (click2_cb), win);
41 gtk_box_append (GTK_BOX (box), btn1); 40
42 gtk_box_append (GTK_BOX (box), btn2); 41 gtk_box_append (GTK_BOX (box), btn1);
43 42 gtk_box_append (GTK_BOX (box), btn2);
44 gtk_widget_show (win); 43
45 } 44 gtk_widget_show (win);
46 45 }
47 int 46
48 main (int argc, char **argv) { 47 int
49 GtkApplication *app; 48 main (int argc, char **argv) {
50 int stat; 49 GtkApplication *app;
51 50 int stat;
52 app = gtk_application_new ("com.github.ToshioCP.lb4", G_APPLICATION_FLAGS_NONE); 51
53 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 52 app = gtk_application_new ("com.github.ToshioCP.lb4", G_APPLICATION_FLAGS_NONE);
54 stat =g_application_run (G_APPLICATION (app), argc, argv); 53 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
55 g_object_unref (app); 54 stat =g_application_run (G_APPLICATION (app), argc, argv);
56 return stat; 55 g_object_unref (app);
57 } 56 return stat;
57 }
~~~
Look at the function `on_activate`. Look at the function `on_activate`.

View file

@ -10,52 +10,54 @@ GtkTextview is a widget for multiline text editing.
GtkTextBuffer is a text buffer which is connected to GtkTextView. GtkTextBuffer is a text buffer which is connected to GtkTextView.
See a sample program `tfv1.c` below. See a sample program `tfv1.c` below.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 on_activate (GApplication *app, gpointer user_data) { 3 static void
5 GtkWidget *win; 4 on_activate (GApplication *app, gpointer user_data) {
6 GtkWidget *tv; 5 GtkWidget *win;
7 GtkTextBuffer *tb; 6 GtkWidget *tv;
8 gchar *text; 7 GtkTextBuffer *tb;
9 8 gchar *text;
10 text = 9
11 "Once upon a time, there was an old man who was called Taketori-no-Okina." 10 text =
12 "It is a japanese word that means a man whose work is making bamboo baskets.\n" 11 "Once upon a time, there was an old man who was called Taketori-no-Okina."
13 "One day, he went into a mountain and found a shining bamboo." 12 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
14 "\"What a mysterious bamboo it is!,\" he said." 13 "One day, he went into a mountain and found a shining bamboo."
15 "He cut it, then there was a small cute baby girl in it." 14 "\"What a mysterious bamboo it is!,\" he said."
16 "The girl was shining faintly." 15 "He cut it, then there was a small cute baby girl in it."
17 "He thought this baby girl is a gift from Heaven and took her home.\n" 16 "The girl was shining faintly."
18 "His wife was surprized at his tale." 17 "He thought this baby girl is a gift from Heaven and took her home.\n"
19 "They were very happy because they had no children." 18 "His wife was surprized at his tale."
20 ; 19 "They were very happy because they had no children."
21 win = gtk_application_window_new (GTK_APPLICATION (app)); 20 ;
22 gtk_window_set_title (GTK_WINDOW (win), "Taketori"); 21 win = gtk_application_window_new (GTK_APPLICATION (app));
23 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 22 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
24 23 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
25 tv = gtk_text_view_new (); 24
26 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 25 tv = gtk_text_view_new ();
27 gtk_text_buffer_set_text (tb, text, -1); 26 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
28 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 27 gtk_text_buffer_set_text (tb, text, -1);
29 28 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
30 gtk_window_set_child (GTK_WINDOW (win), tv); 29
31 30 gtk_window_set_child (GTK_WINDOW (win), tv);
32 gtk_widget_show (win); 31
33 } 32 gtk_widget_show (win);
34 33 }
35 int 34
36 main (int argc, char **argv) { 35 int
37 GtkApplication *app; 36 main (int argc, char **argv) {
38 int stat; 37 GtkApplication *app;
39 38 int stat;
40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE); 39
41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
42 stat =g_application_run (G_APPLICATION (app), argc, argv); 41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
43 g_object_unref (app); 42 stat =g_application_run (G_APPLICATION (app), argc, argv);
44 return stat; 43 g_object_unref (app);
45 } 44 return stat;
46 45 }
46
~~~
Look at line 25. Look at line 25.
GtkTextView is generated and its pointer is assigned to `tv`. GtkTextView is generated and its pointer is assigned to `tv`.
@ -108,56 +110,58 @@ The difference between these two files is very little.
Though you can modify the source file by this diff output, It's good for you to show `tfv2.c`. Though you can modify the source file by this diff output, It's good for you to show `tfv2.c`.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 on_activate (GApplication *app, gpointer user_data) { 3 static void
5 GtkWidget *win; 4 on_activate (GApplication *app, gpointer user_data) {
6 GtkWidget *scr; 5 GtkWidget *win;
7 GtkWidget *tv; 6 GtkWidget *scr;
8 GtkTextBuffer *tb; 7 GtkWidget *tv;
9 gchar *text; 8 GtkTextBuffer *tb;
10 9 gchar *text;
11 text = 10
12 "Once upon a time, there was an old man who was called Taketori-no-Okina." 11 text =
13 "It is a japanese word that means a man whose work is making bamboo baskets.\n" 12 "Once upon a time, there was an old man who was called Taketori-no-Okina."
14 "One day, he went into a mountain and found a shining bamboo." 13 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
15 "\"What a mysterious bamboo it is!,\" he said." 14 "One day, he went into a mountain and found a shining bamboo."
16 "He cut it, then there was a small cute baby girl in it." 15 "\"What a mysterious bamboo it is!,\" he said."
17 "The girl was shining faintly." 16 "He cut it, then there was a small cute baby girl in it."
18 "He thought this baby girl is a gift from Heaven and took her home.\n" 17 "The girl was shining faintly."
19 "His wife was surprized at his tale." 18 "He thought this baby girl is a gift from Heaven and took her home.\n"
20 "They were very happy because they had no children." 19 "His wife was surprized at his tale."
21 ; 20 "They were very happy because they had no children."
22 win = gtk_application_window_new (GTK_APPLICATION (app)); 21 ;
23 gtk_window_set_title (GTK_WINDOW (win), "Taketori"); 22 win = gtk_application_window_new (GTK_APPLICATION (app));
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 23 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
25 24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
26 scr = gtk_scrolled_window_new (); 25
27 gtk_window_set_child (GTK_WINDOW (win), scr); 26 scr = gtk_scrolled_window_new ();
28 27 gtk_window_set_child (GTK_WINDOW (win), scr);
29 tv = gtk_text_view_new (); 28
30 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 29 tv = gtk_text_view_new ();
31 gtk_text_buffer_set_text (tb, text, -1); 30 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
32 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 31 gtk_text_buffer_set_text (tb, text, -1);
33 32 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
34 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 33
35 34 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
36 gtk_widget_show (win); 35
37 } 36 gtk_widget_show (win);
38 37 }
39 int 38
40 main (int argc, char **argv) { 39 int
41 GtkApplication *app; 40 main (int argc, char **argv) {
42 int stat; 41 GtkApplication *app;
43 42 int stat;
44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE); 43
45 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
46 stat =g_application_run (G_APPLICATION (app), argc, argv); 45 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
47 g_object_unref (app); 46 stat =g_application_run (G_APPLICATION (app), argc, argv);
48 return stat; 47 g_object_unref (app);
49 } 48 return stat;
50 49 }
50
~~~
Now compile and run it. Now compile and run it.
This time the window doesn't extend even if you type a lot of characters. This time the window doesn't extend even if you type a lot of characters.

View file

@ -89,62 +89,64 @@ It works as follows.
The program is as follows. The program is as follows.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 on_activate (GApplication *app, gpointer user_data) { 3 static void
5 g_print ("You need a filename argument.\n"); 4 on_activate (GApplication *app, gpointer user_data) {
6 } 5 g_print ("You need a filename argument.\n");
7 6 }
8 static void 7
9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) { 8 static void
10 GtkWidget *win; 9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
11 GtkWidget *scr; 10 GtkWidget *win;
12 GtkWidget *tv; 11 GtkWidget *scr;
13 GtkTextBuffer *tb; 12 GtkWidget *tv;
14 char *contents; 13 GtkTextBuffer *tb;
15 gsize length; 14 char *contents;
16 char *filename; 15 gsize length;
17 16 char *filename;
18 win = gtk_application_window_new (GTK_APPLICATION (app)); 17
19 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 18 win = gtk_application_window_new (GTK_APPLICATION (app));
20 19 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
21 scr = gtk_scrolled_window_new (); 20
22 gtk_window_set_child (GTK_WINDOW (win), scr); 21 scr = gtk_scrolled_window_new ();
23 22 gtk_window_set_child (GTK_WINDOW (win), scr);
24 tv = gtk_text_view_new (); 23
25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 24 tv = gtk_text_view_new ();
26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
27 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE); 26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
28 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 27 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
29 28 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
30 if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) { 29
31 gtk_text_buffer_set_text (tb, contents, length); 30 if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
32 g_free (contents); 31 gtk_text_buffer_set_text (tb, contents, length);
33 filename = g_file_get_basename (files[0]); 32 g_free (contents);
34 gtk_window_set_title (GTK_WINDOW (win), filename); 33 filename = g_file_get_basename (files[0]);
35 g_free (filename); 34 gtk_window_set_title (GTK_WINDOW (win), filename);
36 gtk_widget_show (win); 35 g_free (filename);
37 } else { 36 gtk_widget_show (win);
38 filename = g_file_get_path (files[0]); 37 } else {
39 g_print ("No such file: %s.\n", filename); 38 filename = g_file_get_path (files[0]);
40 gtk_window_destroy (GTK_WINDOW (win)); 39 g_print ("No such file: %s.\n", filename);
41 } 40 gtk_window_destroy (GTK_WINDOW (win));
42 } 41 }
43 42 }
44 int 43
45 main (int argc, char **argv) { 44 int
46 GtkApplication *app; 45 main (int argc, char **argv) {
47 int stat; 46 GtkApplication *app;
48 47 int stat;
49 app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN); 48
50 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 49 app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
51 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL); 50 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
52 stat =g_application_run (G_APPLICATION (app), argc, argv); 51 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
53 g_object_unref (app); 52 stat =g_application_run (G_APPLICATION (app), argc, argv);
54 return stat; 53 g_object_unref (app);
55 } 54 return stat;
56 55 }
56
~~~
Save it as `tfv3.c`. Save it as `tfv3.c`.
Then compile and run it. Then compile and run it.
@ -211,77 +213,79 @@ It is shown in the right screenshot.
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow. GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
Now I want to show you the program `tfv4.c`. Now I want to show you the program `tfv4.c`.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 static void 2
4 on_activate (GApplication *app, gpointer user_data) { 3 static void
5 g_print ("You need a filename argument.\n"); 4 on_activate (GApplication *app, gpointer user_data) {
6 } 5 g_print ("You need a filename argument.\n");
7 6 }
8 static void 7
9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) { 8 static void
10 GtkWidget *win; 9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
11 GtkWidget *nb; 10 GtkWidget *win;
12 GtkWidget *lab; 11 GtkWidget *nb;
13 GtkNotebookPage *nbp; 12 GtkWidget *lab;
14 GtkWidget *scr; 13 GtkNotebookPage *nbp;
15 GtkWidget *tv; 14 GtkWidget *scr;
16 GtkTextBuffer *tb; 15 GtkWidget *tv;
17 char *contents; 16 GtkTextBuffer *tb;
18 gsize length; 17 char *contents;
19 char *filename; 18 gsize length;
20 int i; 19 char *filename;
21 20 int i;
22 win = gtk_application_window_new (GTK_APPLICATION (app)); 21
23 gtk_window_set_title (GTK_WINDOW (win), "file viewer"); 22 win = gtk_application_window_new (GTK_APPLICATION (app));
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 23 gtk_window_set_title (GTK_WINDOW (win), "file viewer");
25 gtk_window_maximize (GTK_WINDOW (win)); 24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
26 25 gtk_window_maximize (GTK_WINDOW (win));
27 nb = gtk_notebook_new (); 26
28 gtk_window_set_child (GTK_WINDOW (win), nb); 27 nb = gtk_notebook_new ();
29 28 gtk_window_set_child (GTK_WINDOW (win), nb);
30 for (i = 0; i < n_files; i++) { 29
31 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) { 30 for (i = 0; i < n_files; i++) {
32 scr = gtk_scrolled_window_new (); 31 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
33 tv = gtk_text_view_new (); 32 scr = gtk_scrolled_window_new ();
34 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 33 tv = gtk_text_view_new ();
35 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 34 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
36 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE); 35 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 36 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
38 37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
39 gtk_text_buffer_set_text (tb, contents, length); 38
40 g_free (contents); 39 gtk_text_buffer_set_text (tb, contents, length);
41 filename = g_file_get_basename (files[i]); 40 g_free (contents);
42 lab = gtk_label_new (filename); 41 filename = g_file_get_basename (files[i]);
43 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab); 42 lab = gtk_label_new (filename);
44 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr); 43 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
45 g_object_set (nbp, "tab-expand", TRUE, NULL); 44 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
46 g_free (filename); 45 g_object_set (nbp, "tab-expand", TRUE, NULL);
47 } else { 46 g_free (filename);
48 filename = g_file_get_path (files[i]); 47 } else {
49 g_print ("No such file: %s.\n", filename); 48 filename = g_file_get_path (files[i]);
50 g_free (filename); 49 g_print ("No such file: %s.\n", filename);
51 } 50 g_free (filename);
52 } 51 }
53 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) 52 }
54 gtk_widget_show (win); 53 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0)
55 else 54 gtk_widget_show (win);
56 gtk_window_destroy (GTK_WINDOW (win)); 55 else
57 } 56 gtk_window_destroy (GTK_WINDOW (win));
58 57 }
59 int 58
60 main (int argc, char **argv) { 59 int
61 GtkApplication *app; 60 main (int argc, char **argv) {
62 int stat; 61 GtkApplication *app;
63 62 int stat;
64 app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN); 63
65 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 64 app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
66 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL); 65 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
67 stat =g_application_run (G_APPLICATION (app), argc, argv); 66 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
68 g_object_unref (app); 67 stat =g_application_run (G_APPLICATION (app), argc, argv);
69 return stat; 68 g_object_unref (app);
70 } 69 return stat;
71 70 }
71
~~~
Most of the change is in the function `on_open`. Most of the change is in the function `on_open`.
The numbers at the left of the following items are line numbers in the source code. The numbers at the left of the following items are line numbers in the source code.

View file

@ -57,39 +57,41 @@ So, I will just show you the way how to write the code and avoid the theoretical
Let's define TfeTextView object which is a child object of GtkTextView. Let's define TfeTextView object which is a child object of GtkTextView.
First, look at the program below. First, look at the program below.
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type () ~~~C
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView) #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
struct _TfeTextView struct _TfeTextView
{ {
GtkTextView parent; GtkTextView parent;
GFile *file; GFile *file;
}; };
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW); G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
static void static void
tfe_text_view_init (TfeTextView *tv) { tfe_text_view_init (TfeTextView *tv) {
} }
static void static void
tfe_text_view_class_init (TfeTextViewClass *class) { tfe_text_view_class_init (TfeTextViewClass *class) {
} }
void void
tfe_text_view_set_file (TfeTextView *tv, GFile *f) { tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
tv -> file = f; tv -> file = f;
} }
GFile * GFile *
tfe_text_view_get_file (TfeTextView *tv) { tfe_text_view_get_file (TfeTextView *tv) {
return tv -> file; return tv -> file;
} }
GtkWidget * GtkWidget *
tfe_text_view_new (void) { tfe_text_view_new (void) {
return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL)); return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
} }
~~~
If you are curious about the background theory of this program, It's very good for you. If you are curious about the background theory of this program, It's very good for you.
Because to know the theory is very important for you to program GTK applications. Because to know the theory is very important for you to program GTK applications.
@ -157,31 +159,33 @@ The argument win is GtkApplicationWindow, in which the signal "close-request" is
`G_CALLBACK` cast is necessary for the handler. `G_CALLBACK` cast is necessary for the handler.
The program of before\_close is as follows. The program of before\_close is as follows.
1 static gboolean ~~~C
2 before_close (GtkWindow *win, GtkWidget *nb) { 1 static gboolean
3 GtkWidget *scr; 2 before_close (GtkWindow *win, GtkWidget *nb) {
4 GtkWidget *tv; 3 GtkWidget *scr;
5 GFile *file; 4 GtkWidget *tv;
6 GtkTextBuffer *tb; 5 GFile *file;
7 GtkTextIter start_iter; 6 GtkTextBuffer *tb;
8 GtkTextIter end_iter; 7 GtkTextIter start_iter;
9 char *contents; 8 GtkTextIter end_iter;
10 unsigned int n; 9 char *contents;
11 unsigned int i; 10 unsigned int n;
12 11 unsigned int i;
13 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)); 12
14 for (i = 0; i < n; ++i) { 13 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
15 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i); 14 for (i = 0; i < n; ++i) {
16 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr)); 15 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
17 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv)); 16 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
18 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 17 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
19 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter); 18 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
20 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE); 19 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
21 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) 20 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
22 g_print ("ERROR : Can't save %s.", g_file_get_path (file)); 21 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
23 } 22 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
24 return FALSE; 23 }
25 } 24 return FALSE;
25 }
~~~
The numbers on the left of items are line numbers in the source code. The numbers on the left of items are line numbers in the source code.
@ -195,142 +199,144 @@ The numbers on the left of items are line numbers in the source code.
Now I will show you all the source code of `tfe1`.c. Now I will show you all the source code of `tfe1`.c.
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 /* Define TfeTextView Widget which is the child object of GtkTextView */ 2
4 3 /* Define TfeTextView Widget which is the child object of GtkTextView */
5 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type () 4
6 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView) 5 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
7 6 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
8 struct _TfeTextView 7
9 { 8 struct _TfeTextView
10 GtkTextView parent; 9 {
11 GFile *file; 10 GtkTextView parent;
12 }; 11 GFile *file;
13 12 };
14 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW); 13
15 14 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
16 static void 15
17 tfe_text_view_init (TfeTextView *tv) { 16 static void
18 } 17 tfe_text_view_init (TfeTextView *tv) {
19 18 }
20 static void 19
21 tfe_text_view_class_init (TfeTextViewClass *class) { 20 static void
22 } 21 tfe_text_view_class_init (TfeTextViewClass *class) {
23 22 }
24 void 23
25 tfe_text_view_set_file (TfeTextView *tv, GFile *f) { 24 void
26 tv -> file = f; 25 tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
27 } 26 tv -> file = f;
28 27 }
29 GFile * 28
30 tfe_text_view_get_file (TfeTextView *tv) { 29 GFile *
31 return tv -> file; 30 tfe_text_view_get_file (TfeTextView *tv) {
32 } 31 return tv -> file;
33 32 }
34 GtkWidget * 33
35 tfe_text_view_new (void) { 34 GtkWidget *
36 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL)); 35 tfe_text_view_new (void) {
37 } 36 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
38 37 }
39 /* ---------- end of the definition of TfeTextView ---------- */ 38
40 39 /* ---------- end of the definition of TfeTextView ---------- */
41 static gboolean 40
42 before_close (GtkWindow *win, GtkWidget *nb) { 41 static gboolean
43 GtkWidget *scr; 42 before_close (GtkWindow *win, GtkWidget *nb) {
44 GtkWidget *tv; 43 GtkWidget *scr;
45 GFile *file; 44 GtkWidget *tv;
46 GtkTextBuffer *tb; 45 GFile *file;
47 GtkTextIter start_iter; 46 GtkTextBuffer *tb;
48 GtkTextIter end_iter; 47 GtkTextIter start_iter;
49 char *contents; 48 GtkTextIter end_iter;
50 unsigned int n; 49 char *contents;
51 unsigned int i; 50 unsigned int n;
52 51 unsigned int i;
53 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)); 52
54 for (i = 0; i < n; ++i) { 53 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
55 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i); 54 for (i = 0; i < n; ++i) {
56 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr)); 55 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
57 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv)); 56 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
58 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 57 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
59 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter); 58 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
60 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE); 59 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
61 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) 60 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
62 g_print ("ERROR : Can't save %s.", g_file_get_path (file)); 61 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
63 } 62 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
64 return FALSE; 63 }
65 } 64 return FALSE;
66 65 }
67 static void 66
68 on_activate (GApplication *app, gpointer user_data) { 67 static void
69 g_print ("You need a filename argument.\n"); 68 on_activate (GApplication *app, gpointer user_data) {
70 } 69 g_print ("You need a filename argument.\n");
71 70 }
72 static void 71
73 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) { 72 static void
74 GtkWidget *win; 73 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
75 GtkWidget *nb; 74 GtkWidget *win;
76 GtkWidget *lab; 75 GtkWidget *nb;
77 GtkNotebookPage *nbp; 76 GtkWidget *lab;
78 GtkWidget *scr; 77 GtkNotebookPage *nbp;
79 GtkWidget *tv; 78 GtkWidget *scr;
80 GtkTextBuffer *tb; 79 GtkWidget *tv;
81 char *contents; 80 GtkTextBuffer *tb;
82 gsize length; 81 char *contents;
83 char *filename; 82 gsize length;
84 int i; 83 char *filename;
85 84 int i;
86 win = gtk_application_window_new (GTK_APPLICATION (app)); 85
87 gtk_window_set_title (GTK_WINDOW (win), "file editor"); 86 win = gtk_application_window_new (GTK_APPLICATION (app));
88 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300); 87 gtk_window_set_title (GTK_WINDOW (win), "file editor");
89 gtk_window_maximize (GTK_WINDOW (win)); 88 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
90 89 gtk_window_maximize (GTK_WINDOW (win));
91 nb = gtk_notebook_new (); 90
92 gtk_window_set_child (GTK_WINDOW (win), nb); 91 nb = gtk_notebook_new ();
93 92 gtk_window_set_child (GTK_WINDOW (win), nb);
94 for (i = 0; i < n_files; i++) { 93
95 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) { 94 for (i = 0; i < n_files; i++) {
96 scr = gtk_scrolled_window_new (); 95 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
97 tv = tfe_text_view_new (); 96 scr = gtk_scrolled_window_new ();
98 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 97 tv = tfe_text_view_new ();
99 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 98 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
100 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 99 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
101 100 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
102 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i])); 101
103 gtk_text_buffer_set_text (tb, contents, length); 102 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
104 g_free (contents); 103 gtk_text_buffer_set_text (tb, contents, length);
105 filename = g_file_get_basename (files[i]); 104 g_free (contents);
106 lab = gtk_label_new (filename); 105 filename = g_file_get_basename (files[i]);
107 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab); 106 lab = gtk_label_new (filename);
108 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr); 107 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
109 g_object_set (nbp, "tab-expand", TRUE, NULL); 108 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
110 g_free (filename); 109 g_object_set (nbp, "tab-expand", TRUE, NULL);
111 } else { 110 g_free (filename);
112 filename = g_file_get_path (files[i]); 111 } else {
113 g_print ("No such file: %s.\n", filename); 112 filename = g_file_get_path (files[i]);
114 g_free (filename); 113 g_print ("No such file: %s.\n", filename);
115 } 114 g_free (filename);
116 } 115 }
117 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) { 116 }
118 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb); 117 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
119 gtk_widget_show (win); 118 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
120 } else 119 gtk_widget_show (win);
121 gtk_window_destroy (GTK_WINDOW (win)); 120 } else
122 } 121 gtk_window_destroy (GTK_WINDOW (win));
123 122 }
124 int 123
125 main (int argc, char **argv) { 124 int
126 GtkApplication *app; 125 main (int argc, char **argv) {
127 int stat; 126 GtkApplication *app;
128 127 int stat;
129 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN); 128
130 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 129 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
131 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL); 130 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
132 stat =g_application_run (G_APPLICATION (app), argc, argv); 131 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
133 g_object_unref (app); 132 stat =g_application_run (G_APPLICATION (app), argc, argv);
134 return stat; 133 g_object_unref (app);
135 } 134 return stat;
136 135 }
136
~~~
- 102: set the pointer to GFile into TfeTextView. - 102: set the pointer to GFile into TfeTextView.
`files[i]` is a pointer to GFile structure. `files[i]` is a pointer to GFile structure.

View file

@ -1,6 +1,6 @@
Up: [Readme.md](../Readme.md), Prev: [Section 7](sec7.md), Next: [Section 9](sec9.md) Up: [Readme.md](../Readme.md), Prev: [Section 7](sec7.md), Next: [Section 9](sec9.md)
# Ui file and GtkBuiler # Ui file and GtkBuilder
## New, open and save button ## New, open and save button
@ -16,92 +16,94 @@ Signals and handlers will be explained later.
The screenshot above shows the layout. The screenshot above shows the layout.
The function `on_open` in the source code `tfe2.c` is as follows. The function `on_open` in the source code `tfe2.c` is as follows.
1 static void ~~~C
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) { 1 static void
3 GtkWidget *win; 2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
4 GtkWidget *nb; 3 GtkWidget *win;
5 GtkWidget *lab; 4 GtkWidget *nb;
6 GtkNotebookPage *nbp; 5 GtkWidget *lab;
7 GtkWidget *scr; 6 GtkNotebookPage *nbp;
8 GtkWidget *tv; 7 GtkWidget *scr;
9 GtkTextBuffer *tb; 8 GtkWidget *tv;
10 char *contents; 9 GtkTextBuffer *tb;
11 gsize length; 10 char *contents;
12 char *filename; 11 gsize length;
13 int i; 12 char *filename;
14 13 int i;
15 GtkWidget *boxv; 14
16 GtkWidget *boxh; 15 GtkWidget *boxv;
17 GtkWidget *dmy1; 16 GtkWidget *boxh;
18 GtkWidget *dmy2; 17 GtkWidget *dmy1;
19 GtkWidget *dmy3; 18 GtkWidget *dmy2;
20 GtkWidget *btnn; /* button for new */ 19 GtkWidget *dmy3;
21 GtkWidget *btno; /* button for open */ 20 GtkWidget *btnn; /* button for new */
22 GtkWidget *btns; /* button for save */ 21 GtkWidget *btno; /* button for open */
23 GtkWidget *btnc; /* button for close */ 22 GtkWidget *btns; /* button for save */
24 23 GtkWidget *btnc; /* button for close */
25 win = gtk_application_window_new (GTK_APPLICATION (app)); 24
26 gtk_window_set_title (GTK_WINDOW (win), "file editor"); 25 win = gtk_application_window_new (GTK_APPLICATION (app));
27 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400); 26 gtk_window_set_title (GTK_WINDOW (win), "file editor");
28 27 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
29 boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 28
30 gtk_window_set_child (GTK_WINDOW (win), boxv); 29 boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
31 30 gtk_window_set_child (GTK_WINDOW (win), boxv);
32 boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); 31
33 gtk_box_append (GTK_BOX (boxv), boxh); 32 boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
34 33 gtk_box_append (GTK_BOX (boxv), boxh);
35 dmy1 = gtk_label_new(NULL); /* dummy label for left space */ 34
36 gtk_label_set_width_chars (GTK_LABEL (dmy1), 10); 35 dmy1 = gtk_label_new(NULL); /* dummy label for left space */
37 dmy2 = gtk_label_new(NULL); /* dummy label for center space */ 36 gtk_label_set_width_chars (GTK_LABEL (dmy1), 10);
38 gtk_widget_set_hexpand (dmy2, TRUE); 37 dmy2 = gtk_label_new(NULL); /* dummy label for center space */
39 dmy3 = gtk_label_new(NULL); /* dummy label for right space */ 38 gtk_widget_set_hexpand (dmy2, TRUE);
40 gtk_label_set_width_chars (GTK_LABEL (dmy3), 10); 39 dmy3 = gtk_label_new(NULL); /* dummy label for right space */
41 btnn = gtk_button_new_with_label ("New"); 40 gtk_label_set_width_chars (GTK_LABEL (dmy3), 10);
42 btno = gtk_button_new_with_label ("Open"); 41 btnn = gtk_button_new_with_label ("New");
43 btns = gtk_button_new_with_label ("Save"); 42 btno = gtk_button_new_with_label ("Open");
44 btnc = gtk_button_new_with_label ("Close"); 43 btns = gtk_button_new_with_label ("Save");
45 44 btnc = gtk_button_new_with_label ("Close");
46 gtk_box_append (GTK_BOX (boxh), dmy1); 45
47 gtk_box_append (GTK_BOX (boxh), btnn); 46 gtk_box_append (GTK_BOX (boxh), dmy1);
48 gtk_box_append (GTK_BOX (boxh), btno); 47 gtk_box_append (GTK_BOX (boxh), btnn);
49 gtk_box_append (GTK_BOX (boxh), dmy2); 48 gtk_box_append (GTK_BOX (boxh), btno);
50 gtk_box_append (GTK_BOX (boxh), btns); 49 gtk_box_append (GTK_BOX (boxh), dmy2);
51 gtk_box_append (GTK_BOX (boxh), btnc); 50 gtk_box_append (GTK_BOX (boxh), btns);
52 gtk_box_append (GTK_BOX (boxh), dmy3); 51 gtk_box_append (GTK_BOX (boxh), btnc);
53 52 gtk_box_append (GTK_BOX (boxh), dmy3);
54 nb = gtk_notebook_new (); 53
55 gtk_widget_set_hexpand (nb, TRUE); 54 nb = gtk_notebook_new ();
56 gtk_widget_set_vexpand (nb, TRUE); 55 gtk_widget_set_hexpand (nb, TRUE);
57 gtk_box_append (GTK_BOX (boxv), nb); 56 gtk_widget_set_vexpand (nb, TRUE);
58 57 gtk_box_append (GTK_BOX (boxv), nb);
59 for (i = 0; i < n_files; i++) { 58
60 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) { 59 for (i = 0; i < n_files; i++) {
61 scr = gtk_scrolled_window_new (); 60 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
62 tv = tfe_text_view_new (); 61 scr = gtk_scrolled_window_new ();
63 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 62 tv = tfe_text_view_new ();
64 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 63 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
65 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 64 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
66 65 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
67 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i])); 66
68 gtk_text_buffer_set_text (tb, contents, length); 67 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
69 g_free (contents); 68 gtk_text_buffer_set_text (tb, contents, length);
70 filename = g_file_get_basename (files[i]); 69 g_free (contents);
71 lab = gtk_label_new (filename); 70 filename = g_file_get_basename (files[i]);
72 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab); 71 lab = gtk_label_new (filename);
73 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr); 72 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
74 g_object_set (nbp, "tab-expand", TRUE, NULL); 73 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
75 g_free (filename); 74 g_object_set (nbp, "tab-expand", TRUE, NULL);
76 } else { 75 g_free (filename);
77 filename = g_file_get_path (files[i]); 76 } else {
78 g_print ("No such file: %s.\n", filename); 77 filename = g_file_get_path (files[i]);
79 g_free (filename); 78 g_print ("No such file: %s.\n", filename);
80 } 79 g_free (filename);
81 } 80 }
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) { 81 }
83 gtk_widget_show (win); 82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
84 } else 83 gtk_widget_show (win);
85 gtk_window_destroy (GTK_WINDOW (win)); 84 } else
86 } 85 gtk_window_destroy (GTK_WINDOW (win));
86 }
~~~
The point is how to build the window. The point is how to build the window.
@ -135,65 +137,67 @@ It reduces the cumbersom work.
First, let's look at the ui file `tfe3.ui` that defines a structure of the widgets. First, let's look at the ui file `tfe3.ui` that defines a structure of the widgets.
1 <interface> ~~~xml
2 <object class="GtkApplicationWindow" id="win"> 1 <interface>
3 <property name="title">file editor</property> 2 <object class="GtkApplicationWindow" id="win">
4 <property name="default-width">600</property> 3 <property name="title">file editor</property>
5 <property name="default-height">400</property> 4 <property name="default-width">600</property>
6 <child> 5 <property name="default-height">400</property>
7 <object class="GtkBox" id="boxv"> 6 <child>
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property> 7 <object class="GtkBox" id="boxv">
9 <child> 8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
10 <object class="GtkBox" id="boxh"> 9 <child>
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> 10 <object class="GtkBox" id="boxh">
12 <child> 11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
13 <object class="GtkLabel" id="dmy1"> 12 <child>
14 <property name="width-chars">10</property> 13 <object class="GtkLabel" id="dmy1">
15 </object> 14 <property name="width-chars">10</property>
16 </child> 15 </object>
17 <child> 16 </child>
18 <object class="GtkButton" id="btnn"> 17 <child>
19 <property name="label">New</property> 18 <object class="GtkButton" id="btnn">
20 </object> 19 <property name="label">New</property>
21 </child> 20 </object>
22 <child> 21 </child>
23 <object class="GtkButton" id="btno"> 22 <child>
24 <property name="label">Open</property> 23 <object class="GtkButton" id="btno">
25 </object> 24 <property name="label">Open</property>
26 </child> 25 </object>
27 <child> 26 </child>
28 <object class="GtkLabel" id="dmy2"> 27 <child>
29 <property name="hexpand">TRUE</property> 28 <object class="GtkLabel" id="dmy2">
30 </object> 29 <property name="hexpand">TRUE</property>
31 </child> 30 </object>
32 <child> 31 </child>
33 <object class="GtkButton" id="btns"> 32 <child>
34 <property name="label">Save</property> 33 <object class="GtkButton" id="btns">
35 </object> 34 <property name="label">Save</property>
36 </child> 35 </object>
37 <child> 36 </child>
38 <object class="GtkButton" id="btnc"> 37 <child>
39 <property name="label">Close</property> 38 <object class="GtkButton" id="btnc">
40 </object> 39 <property name="label">Close</property>
41 </child> 40 </object>
42 <child> 41 </child>
43 <object class="GtkLabel" id="dmy3"> 42 <child>
44 <property name="width-chars">10</property> 43 <object class="GtkLabel" id="dmy3">
45 </object> 44 <property name="width-chars">10</property>
46 </child> 45 </object>
47 </object> 46 </child>
48 </child> 47 </object>
49 <child> 48 </child>
50 <object class="GtkNotebook" id="nb"> 49 <child>
51 <property name="hexpand">TRUE</property> 50 <object class="GtkNotebook" id="nb">
52 <property name="vexpand">TRUE</property> 51 <property name="hexpand">TRUE</property>
53 </object> 52 <property name="vexpand">TRUE</property>
54 </child> 53 </object>
55 </object> 54 </child>
56 </child> 55 </object>
57 </object> 56 </child>
58 </interface> 57 </object>
59 58 </interface>
59
~~~
This is coded with XML structure. This is coded with XML structure.
Constructs begin with `<` and end with `>` is called tags. Constructs begin with `<` and end with `>` is called tags.
@ -216,12 +220,14 @@ Those two decribe the same structure of widgets.
GtkBuilder builds widgets based on the ui file. GtkBuilder builds widgets based on the ui file.
GtkBuilder *build; ~~~C
GtkBuilder *build;
build = gtk_builder_new_from_file ("tfe3.ui"); build = gtk_builder_new_from_file ("tfe3.ui");
win = GTK_WIDGET (gtk_builder_get_object (build, "win")); win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app)); gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
nb = GTK_WIDGET (gtk_builder_get_object (build, "nb")); nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
~~~
The function `gtk_builder_new_from_file` reads the file given as an argument, build the widgets, generate GtkBuilder object and set pointers to the widgets in it. The function `gtk_builder_new_from_file` reads the file given as an argument, build the widgets, generate GtkBuilder object and set pointers to the widgets in it.
The function `gtk_builder_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file. The function `gtk_builder_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file.
@ -295,54 +301,56 @@ Using ui file not only shortens C source files, but also makes the widgets' stru
Now I'll show you the C source code `tfe3.c`. Now I'll show you the C source code `tfe3.c`.
Only functions `on_open` are shown as follows. Only functions `on_open` are shown as follows.
1 static void ~~~C
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) { 1 static void
3 GtkWidget *win; 2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
4 GtkWidget *nb; 3 GtkWidget *win;
5 GtkWidget *lab; 4 GtkWidget *nb;
6 GtkNotebookPage *nbp; 5 GtkWidget *lab;
7 GtkWidget *scr; 6 GtkNotebookPage *nbp;
8 GtkWidget *tv; 7 GtkWidget *scr;
9 GtkTextBuffer *tb; 8 GtkWidget *tv;
10 char *contents; 9 GtkTextBuffer *tb;
11 gsize length; 10 char *contents;
12 char *filename; 11 gsize length;
13 int i; 12 char *filename;
14 GtkBuilder *build; 13 int i;
15 14 GtkBuilder *build;
16 build = gtk_builder_new_from_file ("tfe3.ui"); 15
17 win = GTK_WIDGET (gtk_builder_get_object (build, "win")); 16 build = gtk_builder_new_from_file ("tfe3.ui");
18 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app)); 17 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
19 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb")); 18 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
20 g_object_unref(build); 19 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
21 for (i = 0; i < n_files; i++) { 20 g_object_unref(build);
22 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) { 21 for (i = 0; i < n_files; i++) {
23 scr = gtk_scrolled_window_new (); 22 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
24 tv = tfe_text_view_new (); 23 scr = gtk_scrolled_window_new ();
25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 24 tv = tfe_text_view_new ();
26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
27 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
28 27 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
29 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i])); 28
30 gtk_text_buffer_set_text (tb, contents, length); 29 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
31 g_free (contents); 30 gtk_text_buffer_set_text (tb, contents, length);
32 filename = g_file_get_basename (files[i]); 31 g_free (contents);
33 lab = gtk_label_new (filename); 32 filename = g_file_get_basename (files[i]);
34 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab); 33 lab = gtk_label_new (filename);
35 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr); 34 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
36 g_object_set (nbp, "tab-expand", TRUE, NULL); 35 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
37 g_free (filename); 36 g_object_set (nbp, "tab-expand", TRUE, NULL);
38 } else { 37 g_free (filename);
39 filename = g_file_get_path (files[i]); 38 } else {
40 g_print ("No such file: %s.\n", filename); 39 filename = g_file_get_path (files[i]);
41 g_free (filename); 40 g_print ("No such file: %s.\n", filename);
42 } 41 g_free (filename);
43 } 42 }
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) { 43 }
45 gtk_widget_show (win); 44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
46 } else 45 gtk_widget_show (win);
47 gtk_window_destroy (GTK_WINDOW (win)); 46 } else
48 } 47 gtk_window_destroy (GTK_WINDOW (win));
48 }
~~~
The source code of `tfe3.c` is stored in [src/tfe](https://github.com/ToshioCP/Gtk4-tutorial/tree/main/src/tfe) directory. The source code of `tfe3.c` is stored in [src/tfe](https://github.com/ToshioCP/Gtk4-tutorial/tree/main/src/tfe) directory.
If you want to see it, click the link above. If you want to see it, click the link above.
@ -353,22 +361,24 @@ In the same way, you can get the source files below in the directory [src/tfe](h
GtkBuilder can build widgets using string. GtkBuilder can build widgets using string.
Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file. Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file.
char *uistring; ~~~C
char *uistring;
uistring = uistring =
"<interface>" "<interface>"
"<object class="GtkApplicationWindow" id="win">" "<object class="GtkApplicationWindow" id="win">"
"<property name=\"title\">file editor</property>" "<property name=\"title\">file editor</property>"
"<property name=\"default-width\">600</property>" "<property name=\"default-width\">600</property>"
"<property name=\"default-height\">400</property>" "<property name=\"default-height\">400</property>"
"<child>" "<child>"
"<object class=\"GtkBox\" id=\"boxv\">" "<object class=\"GtkBox\" id=\"boxv\">"
"<property name="orientation">GTK_ORIENTATION_VERTICAL</property>" "<property name="orientation">GTK_ORIENTATION_VERTICAL</property>"
... ... ... ... ... ...
... ... ... ... ... ...
"</interface>"; "</interface>";
build = gtk_builder_new_from_stringfile (uistring); build = gtk_builder_new_from_stringfile (uistring);
~~~
This method has an advantage and disadvantage. This method has an advantage and disadvantage.
The advantage is that the ui string is written in the source code. The advantage is that the ui string is written in the source code.
@ -390,12 +400,14 @@ And after compilation, it bundles them up into one Gresource object.
An xml file is necessary for the resource compiler `glib-compile-resources`. An xml file is necessary for the resource compiler `glib-compile-resources`.
It describes resource files. It describes resource files.
1 <?xml version="1.0" encoding="UTF-8"?> ~~~xml
2 <gresources> 1 <?xml version="1.0" encoding="UTF-8"?>
3 <gresource prefix="/com/github/ToshioCP/tfe3"> 2 <gresources>
4 <file>tfe3.ui</file> 3 <gresource prefix="/com/github/ToshioCP/tfe3">
5 </gresource> 4 <file>tfe3.ui</file>
6 </gresources> 5 </gresource>
6 </gresources>
~~~
- 2: gresources tag can include mulitple gresources (gresource tags). - 2: gresources tag can include mulitple gresources (gresource tags).
However, this xml has only one gresource. However, this xml has only one gresource.
@ -441,12 +453,14 @@ Now run the compiler.
Then a C source file `resources.c` is generated. Then a C source file `resources.c` is generated.
Modify tfe3.c and save it as tfe3_r.c Modify tfe3.c and save it as tfe3_r.c
# include "resources.c" ~~~C
... ... ... #include "resources.c"
... ... ... ... ... ...
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui"); ... ... ...
... ... ... build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
... ... ... ... ... ...
... ... ...
~~~
Then, compile and run it. Then, compile and run it.
The window appears and it is the same as the screenshot at the beginning of this page. The window appears and it is the same as the screenshot at the beginning of this page.

View file

@ -42,201 +42,211 @@ All the source files are listed below.
`tfetextview.h` `tfetextview.h`
1 #include <gtk/gtk.h> ~~~C
2 1 #include <gtk/gtk.h>
3 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type () 2
4 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView) 3 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
5 4 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
6 void 5
7 tfe_text_view_set_file (TfeTextView *tv, GFile *f); 6 void
8 7 tfe_text_view_set_file (TfeTextView *tv, GFile *f);
9 GFile * 8
10 tfe_text_view_get_file (TfeTextView *tv); 9 GFile *
11 10 tfe_text_view_get_file (TfeTextView *tv);
12 GtkWidget * 11
13 tfe_text_view_new (void); 12 GtkWidget *
14 13 tfe_text_view_new (void);
14
~~~
`tfetextview.c` `tfetextview.c`
1 #include <gtk/gtk.h> ~~~C
2 #include "tfetextview.h" 1 #include <gtk/gtk.h>
3 2 #include "tfetextview.h"
4 struct _TfeTextView 3
5 { 4 struct _TfeTextView
6 GtkTextView parent; 5 {
7 GFile *file; 6 GtkTextView parent;
8 }; 7 GFile *file;
9 8 };
10 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW); 9
11 10 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
12 static void 11
13 tfe_text_view_init (TfeTextView *tv) { 12 static void
14 } 13 tfe_text_view_init (TfeTextView *tv) {
15 14 }
16 static void 15
17 tfe_text_view_class_init (TfeTextViewClass *class) { 16 static void
18 } 17 tfe_text_view_class_init (TfeTextViewClass *class) {
19 18 }
20 void 19
21 tfe_text_view_set_file (TfeTextView *tv, GFile *f) { 20 void
22 tv -> file = f; 21 tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
23 } 22 tv -> file = f;
24 23 }
25 GFile * 24
26 tfe_text_view_get_file (TfeTextView *tv) { 25 GFile *
27 return tv -> file; 26 tfe_text_view_get_file (TfeTextView *tv) {
28 } 27 return tv -> file;
29 28 }
30 GtkWidget * 29
31 tfe_text_view_new (void) { 30 GtkWidget *
32 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL)); 31 tfe_text_view_new (void) {
33 } 32 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
34 33 }
34
~~~
`tfe.c` `tfe.c`
1 #include <gtk/gtk.h> ~~~C
2 #include "tfetextview.h" 1 #include <gtk/gtk.h>
3 2 #include "tfetextview.h"
4 static void 3
5 on_activate (GApplication *app, gpointer user_data) { 4 static void
6 g_print ("You need a filename argument.\n"); 5 on_activate (GApplication *app, gpointer user_data) {
7 } 6 g_print ("You need a filename argument.\n");
8 7 }
9 static void 8
10 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) { 9 static void
11 GtkWidget *win; 10 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
12 GtkWidget *nb; 11 GtkWidget *win;
13 GtkWidget *lab; 12 GtkWidget *nb;
14 GtkNotebookPage *nbp; 13 GtkWidget *lab;
15 GtkWidget *scr; 14 GtkNotebookPage *nbp;
16 GtkWidget *tv; 15 GtkWidget *scr;
17 GtkTextBuffer *tb; 16 GtkWidget *tv;
18 char *contents; 17 GtkTextBuffer *tb;
19 gsize length; 18 char *contents;
20 char *filename; 19 gsize length;
21 int i; 20 char *filename;
22 GtkBuilder *build; 21 int i;
23 22 GtkBuilder *build;
24 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe.ui"); 23
25 win = GTK_WIDGET (gtk_builder_get_object (build, "win")); 24 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe.ui");
26 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app)); 25 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
27 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb")); 26 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
28 g_object_unref (build); 27 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
29 for (i = 0; i < n_files; i++) { 28 g_object_unref (build);
30 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) { 29 for (i = 0; i < n_files; i++) {
31 scr = gtk_scrolled_window_new (); 30 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
32 tv = tfe_text_view_new (); 31 scr = gtk_scrolled_window_new ();
33 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv)); 32 tv = tfe_text_view_new ();
34 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR); 33 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
35 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv); 34 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
36 35 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
37 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i])); 36
38 gtk_text_buffer_set_text (tb, contents, length); 37 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
39 g_free (contents); 38 gtk_text_buffer_set_text (tb, contents, length);
40 filename = g_file_get_basename (files[i]); 39 g_free (contents);
41 lab = gtk_label_new (filename); 40 filename = g_file_get_basename (files[i]);
42 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab); 41 lab = gtk_label_new (filename);
43 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr); 42 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
44 g_object_set (nbp, "tab-expand", TRUE, NULL); 43 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
45 g_free (filename); 44 g_object_set (nbp, "tab-expand", TRUE, NULL);
46 } else { 45 g_free (filename);
47 filename = g_file_get_path (files[i]); 46 } else {
48 g_print ("No such file: %s.\n", filename); 47 filename = g_file_get_path (files[i]);
49 g_free (filename); 48 g_print ("No such file: %s.\n", filename);
50 } 49 g_free (filename);
51 } 50 }
52 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) { 51 }
53 gtk_widget_show (win); 52 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
54 } else 53 gtk_widget_show (win);
55 gtk_window_destroy (GTK_WINDOW (win)); 54 } else
56 } 55 gtk_window_destroy (GTK_WINDOW (win));
57 56 }
58 int 57
59 main (int argc, char **argv) { 58 int
60 GtkApplication *app; 59 main (int argc, char **argv) {
61 int stat; 60 GtkApplication *app;
62 61 int stat;
63 app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN); 62
64 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); 63 app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
65 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL); 64 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
66 stat =g_application_run (G_APPLICATION (app), argc, argv); 65 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
67 g_object_unref (app); 66 stat =g_application_run (G_APPLICATION (app), argc, argv);
68 return stat; 67 g_object_unref (app);
69 } 68 return stat;
70 69 }
70
~~~
`tfe.ui` `tfe.ui`
1 <interface> ~~~xml
2 <object class="GtkApplicationWindow" id="win"> 1 <interface>
3 <property name="title">file editor</property> 2 <object class="GtkApplicationWindow" id="win">
4 <property name="default-width">600</property> 3 <property name="title">file editor</property>
5 <property name="default-height">400</property> 4 <property name="default-width">600</property>
6 <child> 5 <property name="default-height">400</property>
7 <object class="GtkBox" id="boxv"> 6 <child>
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property> 7 <object class="GtkBox" id="boxv">
9 <child> 8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
10 <object class="GtkBox" id="boxh"> 9 <child>
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> 10 <object class="GtkBox" id="boxh">
12 <child> 11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
13 <object class="GtkLabel" id="dmy1"> 12 <child>
14 <property name="width-chars">10</property> 13 <object class="GtkLabel" id="dmy1">
15 </object> 14 <property name="width-chars">10</property>
16 </child> 15 </object>
17 <child> 16 </child>
18 <object class="GtkButton" id="btnn"> 17 <child>
19 <property name="label">New</property> 18 <object class="GtkButton" id="btnn">
20 </object> 19 <property name="label">New</property>
21 </child> 20 </object>
22 <child> 21 </child>
23 <object class="GtkButton" id="btno"> 22 <child>
24 <property name="label">Open</property> 23 <object class="GtkButton" id="btno">
25 </object> 24 <property name="label">Open</property>
26 </child> 25 </object>
27 <child> 26 </child>
28 <object class="GtkLabel" id="dmy2"> 27 <child>
29 <property name="hexpand">TRUE</property> 28 <object class="GtkLabel" id="dmy2">
30 </object> 29 <property name="hexpand">TRUE</property>
31 </child> 30 </object>
32 <child> 31 </child>
33 <object class="GtkButton" id="btns"> 32 <child>
34 <property name="label">Save</property> 33 <object class="GtkButton" id="btns">
35 </object> 34 <property name="label">Save</property>
36 </child> 35 </object>
37 <child> 36 </child>
38 <object class="GtkButton" id="btnc"> 37 <child>
39 <property name="label">Close</property> 38 <object class="GtkButton" id="btnc">
40 </object> 39 <property name="label">Close</property>
41 </child> 40 </object>
42 <child> 41 </child>
43 <object class="GtkLabel" id="dmy3"> 42 <child>
44 <property name="width-chars">10</property> 43 <object class="GtkLabel" id="dmy3">
45 </object> 44 <property name="width-chars">10</property>
46 </child> 45 </object>
47 </object> 46 </child>
48 </child> 47 </object>
49 <child> 48 </child>
50 <object class="GtkNotebook" id="nb"> 49 <child>
51 <property name="hexpand">TRUE</property> 50 <object class="GtkNotebook" id="nb">
52 <property name="vexpand">TRUE</property> 51 <property name="hexpand">TRUE</property>
53 </object> 52 <property name="vexpand">TRUE</property>
54 </child> 53 </object>
55 </object> 54 </child>
56 </child> 55 </object>
57 </object> 56 </child>
58 </interface> 57 </object>
59 58 </interface>
59
~~~
`tfe.gresource.xml` `tfe.gresource.xml`
1 <?xml version="1.0" encoding="UTF-8"?> ~~~xml
2 <gresources> 1 <?xml version="1.0" encoding="UTF-8"?>
3 <gresource prefix="/com/github/ToshioCP/tfe3"> 2 <gresources>
4 <file>tfe.ui</file> 3 <gresource prefix="/com/github/ToshioCP/tfe3">
5 </gresource> 4 <file>tfe.ui</file>
6 </gresources> 5 </gresource>
6 </gresources>
~~~
## Make ## Make
@ -278,25 +288,27 @@ If the modification time of `sample.c` is older then the generation of `sample.o
The Makefile for `tfe` is as follows. The Makefile for `tfe` is as follows.
1 all: tfe ~~~makefile
2 1 all: tfe
3 tfe: tfe.o tfetextview.o resources.o 2
4 gcc -o tfe tfe.o tfetextview.o resources.o `pkg-config --libs gtk4` 3 tfe: tfe.o tfetextview.o resources.o
5 4 gcc -o tfe tfe.o tfetextview.o resources.o `pkg-config --libs gtk4`
6 tfe.o: tfe.c tfetextview.h 5
7 gcc -c -o tfe.o `pkg-config --cflags gtk4` tfe.c 6 tfe.o: tfe.c tfetextview.h
8 tfetextview.o: tfetextview.c tfetextview.h 7 gcc -c -o tfe.o `pkg-config --cflags gtk4` tfe.c
9 gcc -c -o tfetextview.o `pkg-config --cflags gtk4` tfetextview.c 8 tfetextview.o: tfetextview.c tfetextview.h
10 resources.o: resources.c 9 gcc -c -o tfetextview.o `pkg-config --cflags gtk4` tfetextview.c
11 gcc -c -o resources.o `pkg-config --cflags gtk4` resources.c 10 resources.o: resources.c
12 11 gcc -c -o resources.o `pkg-config --cflags gtk4` resources.c
13 resources.c: tfe.gresource.xml tfe.ui 12
14 glib-compile-resources tfe.gresource.xml --target=resources.c --generate-source 13 resources.c: tfe.gresource.xml tfe.ui
15 14 glib-compile-resources tfe.gresource.xml --target=resources.c --generate-source
16 .Phony: clean 15
17 16 .Phony: clean
18 clean: 17
19 rm -f tfe tfe.o tfetextview.o resources.o resources.c 18 clean:
19 rm -f tfe tfe.o tfetextview.o resources.o resources.c
~~~
You only need to type `make`. You only need to type `make`.
@ -324,31 +336,33 @@ However, Ruby is really sophisticated and recommendable script language.
Rake has task and file task, which is similar to target, prerequisite and recipe in make. Rake has task and file task, which is similar to target, prerequisite and recipe in make.
1 require 'rake/clean' ~~~ruby
2 1 require 'rake/clean'
3 targetfile = "tfe" 2
4 srcfiles = FileList["tfe.c", "tfetextview.c", "resources.c"] 3 targetfile = "tfe"
5 rscfile = srcfiles[2] 4 srcfiles = FileList["tfe.c", "tfetextview.c", "resources.c"]
6 objfiles = srcfiles.gsub(/.c$/, '.o') 5 rscfile = srcfiles[2]
7 6 objfiles = srcfiles.gsub(/.c$/, '.o')
8 CLEAN.include(targetfile, objfiles, rscfile) 7
9 8 CLEAN.include(targetfile, objfiles, rscfile)
10 task default: targetfile 9
11 10 task default: targetfile
12 file targetfile => objfiles do |t| 11
13 sh "gcc -o #{t.name} #{t.prerequisites.join(' ')} `pkg-config --libs gtk4`" 12 file targetfile => objfiles do |t|
14 end 13 sh "gcc -o #{t.name} #{t.prerequisites.join(' ')} `pkg-config --libs gtk4`"
15 14 end
16 objfiles.each do |obj| 15
17 src = obj.gsub(/.o$/,'.c') 16 objfiles.each do |obj|
18 file obj => src do |t| 17 src = obj.gsub(/.o$/,'.c')
19 sh "gcc -c -o #{t.name} `pkg-config --cflags gtk4` #{t.source}" 18 file obj => src do |t|
20 end 19 sh "gcc -c -o #{t.name} `pkg-config --cflags gtk4` #{t.source}"
21 end 20 end
22 21 end
23 file rscfile => ["tfe.gresource.xml", "tfe.ui"] do |t| 22
24 sh "glib-compile-resources #{t.prerequisites[0]} --target=#{t.name} --generate-source" 23 file rscfile => ["tfe.gresource.xml", "tfe.ui"] do |t|
25 end 24 sh "glib-compile-resources #{t.prerequisites[0]} --target=#{t.name} --generate-source"
25 end
~~~
What `Rakefile` describes is almost same as `Makefile` in the previous subsection. What `Rakefile` describes is almost same as `Makefile` in the previous subsection.
@ -380,16 +394,18 @@ Many developers are using meson and ninja now.
To use meson, you first need to write `meson.build` file. To use meson, you first need to write `meson.build` file.
1 project('tfe', 'c') ~~~meson
2 1 project('tfe', 'c')
3 gtkdep = dependency('gtk4') 2
4 3 gtkdep = dependency('gtk4')
5 gnome=import('gnome') 4
6 resources = gnome.compile_resources('resources','tfe.gresource.xml') 5 gnome=import('gnome')
7 6 resources = gnome.compile_resources('resources','tfe.gresource.xml')
8 sourcefiles=files('tfe.c', 'tfetextview.c') 7
9 8 sourcefiles=files('tfe.c', 'tfetextview.c')
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep) 9
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
~~~
- 1: The function `project` defines things about the project. - 1: The function `project` defines things about the project.
The first parameter is the name of the project and the second is the programing language. The first parameter is the name of the project and the second is the programing language.

View file

@ -45,16 +45,28 @@ require 'pathname'
# ---- Folding verbatim lines ---- # ---- Folding verbatim lines ----
# When C sourcefiles or subshell output are included, the lines are folded to fit in 'width'. # When C sourcefiles or subshell output are included, the lines are folded to fit in 'width'.
# Before they are folded, four space characters are prepended to the line. # Width must be positive integer.
# Therefore, 'width' must be at least five.
# Otherwise the lines are not folded. # Otherwise the lines are not folded.
# This script uses "fenced code blocks" for verbatim lines.
# It is available in GFM and pandoc's markdown but not in original markdown.
# Two characters backtick (`) and tilde (~) are possible for fences.
# This script uses tilde because info string cannot contain any backticks for the backtick code fence.
# Info string follows opening fence and it is usually a language name.
# ~~~C
# int main (int argc, char **argv) {
# ........
# ~~~
# Then the contents are highlighted based on C language syntax.
# This script find the language by the suffix of the file name.
# .c => C, .h => C, .rb => ruby, Rakefile, => ruby, .xml => xml, .ui => xml, .y => bison, .lex => lex, .build => meson, .md => markdown
# Makefile => makefile
def src2md srcmd, md, width def src2md srcmd, md, width
src_buf = IO.readlines srcmd src_buf = IO.readlines srcmd
src_dir = File.dirname srcmd src_dir = File.dirname srcmd
md_dir = File.dirname md md_dir = File.dirname md
# type is 'the type of the target', which is one of "markdown", "html" and "latex". type = File.basename md_dir # gfm, html or latex
type = md_dir == "." ? "markdown" : md_dir
md_buf = [] md_buf = []
comflag = false comflag = false
@ -65,14 +77,16 @@ def src2md srcmd, md, width
else else
md_buf << " $ "+line md_buf << " $ "+line
`cd #{src_dir}; #{line.chomp}`.each_line do |l| `cd #{src_dir}; #{line.chomp}`.each_line do |l|
md_buf << l.gsub(/^/," ") fold(l, width).each_line do |l2|
md_buf << l2.gsub(/^/," ")
end
end end
end end
elsif line == "$$$\n" elsif line == "$$$\n"
comflag = true comflag = true
elsif line =~ /^@@@\s+(\S+)\s*(.*)\s*$/ elsif line =~ /^@@@\s+(\S+)\s*(.*)$/
c_file = $1 c_file = $1
c_functions = $2.split(" ") c_functions = $2.strip.split(" ")
if c_file =~ /^\// # absolute path if c_file =~ /^\// # absolute path
c_file_buf = IO.readlines(c_file) c_file_buf = IO.readlines(c_file)
else #relative path else #relative path
@ -108,38 +122,33 @@ def src2md srcmd, md, width
end end
end end
end end
md_buf << "~~~#{lang(c_file)}\n"
ln_width = tmp_buf.size.to_s.length ln_width = tmp_buf.size.to_s.length
n = 1 n = 1
tmp_buf.each do |l| tmp_buf.each do |l|
l = sprintf(" %#{ln_width}d %s", n, l) l = sprintf("%#{ln_width}d %s", n, l)
md_buf << l fold(l, width).each_line do |l2|
md_buf << l2
end
n += 1 n += 1
end end
md_buf << "~~~\n"
else else
md_buf << change_rel_link(line, src_dir, File.dirname(md)) line = change_rel_link(line, src_dir, md_dir)
end if type == "latex" # remove relative link
end line.gsub!(/(^|[^!])\[([^\]]*)\]\((?~http)\)/,"\\1\\2")
tmp_buf = md_buf else # type == "gfm" or "html", then remove size option from link to image files.
md_buf = [] line.gsub!(/(!\[[^\]]*\]\([^\)]*\)) *{width *= *\d*(|\.\d*)cm *height *= *\d*(|\.\d*)cm}/,"\\1")
tmp_buf.each do |line|
if line =~ /^ / && width.instance_of?(Integer) && width >= 5
indent = line =~ /^( *\d+ +)/ ? " "*$1.length : " "
while line.instance_of?(String) && line.length > width
md_buf << line[0, width]+"\n"
line = line[width .. -1].gsub(/^/,indent)
end end
elsif type == "latex" md_buf << line
line.gsub!(/(^|[^!])\[([^\]]*)\]\((?~http)\)/,"\\1\\2") # remove link
else # type == "markdown" or "html"
line.gsub!(/(!\[[^\]]*\]\([^\)]*\)) *{width *= *\d*(|\.\d*)cm *height *= *\d*(|\.\d*)cm}/,"\\1") # remove size option from link to image files.
end end
md_buf << line
end end
IO.write(md,md_buf.join) IO.write(md,md_buf.join)
end end
def change_rel_link line, src_dir, basedir # Change the base of relative links from org_dir to new_dir
p_basedir = Pathname.new basedir def change_rel_link line, org_dir, new_dir
p_new_dir = Pathname.new new_dir
left = "" left = ""
right = line right = line
while right =~ /(!?\[[^\]]*\])\(([^\)]*)\)/ while right =~ /(!?\[[^\]]*\])\(([^\)]*)\)/
@ -150,11 +159,42 @@ def change_rel_link line, src_dir, basedir
if name =~ /\[(S|s)ection (\d+)\]/ if name =~ /\[(S|s)ection (\d+)\]/
link = "sec#{$2}.md" link = "sec#{$2}.md"
elsif ! (link =~ /^(http|\/)/) elsif ! (link =~ /^(http|\/)/)
p_link = Pathname.new "#{src_dir}/#{link}" p_link = Pathname.new "#{org_dir}/#{link}"
link = p_link.relative_path_from(p_basedir).to_s link = p_link.relative_path_from(p_new_dir).to_s
end end
left += "#{name}(#{link})" left += "#{name}(#{link})"
end end
left + right left + right
end end
def fold line, width
if width <=0
return line
end
tmp = []
while line.length > width
tmp << line[0, width]+"\n"
line = line[width .. -1]
end
tmp << line
tmp.join
end
def lang file
tbl = {".c" => "C", ".h" => "C", ".rb" => "ruby", ".xml" => "xml", ".ui" => "xml",
".y" => "bison", ".lex" => "lex", ".build" => "meson", ".md" => "markdown" }
name = File.basename file
if name == "Makefile"
return "makefile"
elsif name == "Rakefile"
return "ruby"
else
suffix = File.extname name
tbl.each do |key, val|
if suffix == key
return val
end
end
end
return ""
end

View file

@ -19,7 +19,8 @@ The signal handler will be described after the explanation of this code.
static void static void
on_activate (GApplication *app, gpointer user_data) { on_activate (GApplication *app, gpointer user_data) {
... ... ... ... ... ...
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE)); GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
NULL, g_variant_new_boolean (FALSE));
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen"); GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win); g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
... ... ... ... ... ...
@ -114,7 +115,8 @@ Those colors are given to the signal handler as a parameter.
static void static void
on_activate (GApplication *app, gpointer user_data) { on_activate (GApplication *app, gpointer user_data) {
... ... ... ... ... ...
GSimpleAction *act_color = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red")); GSimpleAction *act_color = g_simple_action_new_stateful ("color",
g_variant_type_new("s"), g_variant_new_string ("red"));
GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red"); GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green"); GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue"); GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
@ -148,7 +150,8 @@ The following is the "activate" signal handler.
static void static void
color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) { color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
gchar *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL)); gchar *color = g_strdup_printf ("label#lb {background-color: %s;}",
g_variant_get_string (parameter, NULL));
gtk_css_provider_load_from_data (provider, color, -1); gtk_css_provider_load_from_data (provider, color, -1);
g_free (color); g_free (color);
g_action_change_state (G_ACTION (action), parameter); g_action_change_state (G_ACTION (action), parameter);

View file

@ -11,22 +11,26 @@ The same goes for menus.
The ui file for menus has interface, menu tags. The ui file for menus has interface, menu tags.
The file starts and ends with interface tag. The file starts and ends with interface tag.
<interface> ~~~xml
<menu id="menubar"> <interface>
</menu> <menu id="menubar">
</interface> </menu>
</interface>
~~~
`menu` tag corresponds to GMenu object. `menu` tag corresponds to GMenu object.
`id` attribute defines the name of the object. `id` attribute defines the name of the object.
It will be refered by GtkBuilder. It will be refered by GtkBuilder.
<submenu> ~~~xml
<attribute name="label">File</attribute> <submenu>
<item> <attribute name="label">File</attribute>
<attribute name="label">New</attribute> <item>
<attribute name="action">win.new</attribute> <attribute name="label">New</attribute>
</item> <attribute name="action">win.new</attribute>
</submenu> </item>
</submenu>
~~~
`item` tag corresponds to item in GMenu which has the same structure as GMenuItem. `item` tag corresponds to item in GMenu which has the same structure as GMenuItem.
The item above has a label attribute. The item above has a label attribute.
@ -38,15 +42,17 @@ The GMenuItem has a link to GMenu.
The ui file above can be described as follows. The ui file above can be described as follows.
<item> ~~~xml
<attribute name="label">File</attribute> <item>
<link name="submenu"> <attribute name="label">File</attribute>
<item> <link name="submenu">
<attribute name="label">New</attribute> <item>
<attribute name="action">win.new</attribute> <attribute name="label">New</attribute>
</item> <attribute name="action">win.new</attribute>
</link> </item>
</item> </link>
</item>
~~~
`link` tag expresses the link to submenu. `link` tag expresses the link to submenu.
And at the same time it also expresses the submenu itself. And at the same time it also expresses the submenu itself.
@ -69,11 +75,13 @@ The ui file is converted to the resource by the resouce compiler `glib-compile-r
GtkBuilder builds menus from the resource. GtkBuilder builds menus from the resource.
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui"); ~~~C
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")); GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
gtk_application_set_menubar (GTK_APPLICATION (app), menubar); gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
g_object_unref (builder); g_object_unref (builder);
~~~
It is important that `builder` is unreferred after the GMenuModel `menubar` is set to the application. It is important that `builder` is unreferred after the GMenuModel `menubar` is set to the application.
If you do it before setting, bad thing will happen -- your computer might freeze. If you do it before setting, bad thing will happen -- your computer might freeze.
@ -86,31 +94,42 @@ You can implement them easily with GActionEntry structure and `g_action_map_add_
GActionEntry contains action name, signal handlers, parameter and state. GActionEntry contains action name, signal handlers, parameter and state.
typedef struct _GActionEntry GActionEntry; ~~~C
typedef struct _GActionEntry GActionEntry;
struct _GActionEntry
{
const gchar *name; /* action name */
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data); /* activate handler */
const gchar *parameter_type; /* the type of the parameter given as a single GVariant type string */
const gchar *state; /* initial state given in GVariant text format */
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data); /* change-state handler */
/*< private >*/
gsize padding[3];
};
struct _GActionEntry
{
/* action name */
const gchar *name;
/* activate handler */
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
/* the type of the parameter given as a single GVariant type string */
const gchar *parameter_type;
/* initial state given in GVariant text format */
const gchar *state;
/* change-state handler */
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);
/*< private >*/
gsize padding[3];
};
~~~
For example, the actions in the previous section are: For example, the actions in the previous section are:
{ "fullscreen", NULL, NULL, "false", fullscreen_changed } ~~~C
{ "color", color_activated, "s", "red", NULL } { "fullscreen", NULL, NULL, "false", fullscreen_changed }
{ "quit", quit_activated, NULL, NULL, NULL }, { "color", color_activated, "s", "red", NULL }
{ "quit", quit_activated, NULL, NULL, NULL },
~~~
And `g_action_map_add_action_entries` does all the process instead of the functions you have needed. And `g_action_map_add_action_entries` does all the process instead of the functions you have needed.
const GActionEntry app_entries[] = { ~~~C
{ "quit", quit_activated, NULL, NULL, NULL } const GActionEntry app_entries[] = {
}; { "quit", quit_activated, NULL, NULL, NULL }
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app); };
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
G_N_ELEMENTS (app_entries), app);
~~~
The code above does: The code above does:
@ -120,12 +139,14 @@ The code above does:
The same goes for the other actions. The same goes for the other actions.
const GActionEntry win_entries[] = { ~~~C
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }, const GActionEntry win_entries[] = {
{ "color", color_activated, "s", "red", NULL } { "fullscreen", NULL, NULL, "false", fullscreen_changed },
}; { "color", color_activated, "s", "red", NULL }
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win); };
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,
G_N_ELEMENTS (win_entries), win);
~~~
The code above does: The code above does:
- Build a "fullscreen" action and "color" action. - Build a "fullscreen" action and "color" action.

View file

@ -30,7 +30,7 @@ In this section, we don't use it.
That means we only use identity transformation. That means we only use identity transformation.
Therefore, the coordinate in source and mask is the same as the coordinate in destination. Therefore, the coordinate in source and mask is the same as the coordinate in destination.
![Stroke a rectangle](../image/cairo.png) ![Stroke a rectangle](../image/cairo.png){width=9.0cm height=6.0cm}
The instruction is as follows: The instruction is as follows:

View file

@ -141,7 +141,8 @@ Modify `env.sh`.
# compiler # compiler
CPPFLAGS="-I$HOME/local/include" CPPFLAGS="-I$HOME/local/include"
LDFLAGS="-L$HOME/local/lib" LDFLAGS="-L$HOME/local/lib"
PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig:$HOME/local/lib/x86_64-linux-gnu/pkgconfig:$HOME/local/share/pkgconfig" PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig:$HOME/local/lib/x86_64-linux-gnu/pkgconfig:
$HOME/local/share/pkgconfig"
export CPPFLAGS LDFLAGS PKG_CONFIG_PATH export CPPFLAGS LDFLAGS PKG_CONFIG_PATH
# linker # linker
LD_LIBRARY_PATH="$HOME/local/lib/x86_64-linux-gnu/" LD_LIBRARY_PATH="$HOME/local/lib/x86_64-linux-gnu/"

View file

@ -4,7 +4,7 @@ Now, we will make a new application which has GtkDrawingArea and TfeTextView in
Its name is "color". Its name is "color".
If you write a color in TfeTextView and click on the `run` button, then the color of GtkDrawingArea changes to the color given by you. If you write a color in TfeTextView and click on the `run` button, then the color of GtkDrawingArea changes to the color given by you.
![color](../image/color.png) ![color](../image/color.png){width=7.0cm height=5.13cm}
The following colors are available. The following colors are available.

View file

@ -40,7 +40,9 @@ Let's run it.
$ ./a.out $ ./a.out
(a.out:13533): GLib-GIO-WARNING **: 15:30:17.449: Your application does not implement g_application_activate() and has no handlers connected to the "activate" signal. It should do one of these. (a.out:13533): GLib-GIO-WARNING **: 15:30:17.449: Your application does not implement
g_application_activate() and has no handlers connected to the "activate" signal.
It should do one of these.
$ $
Oh, just an error message. Oh, just an error message.

View file

@ -55,39 +55,41 @@ So, I will just show you the way how to write the code and avoid the theoretical
Let's define TfeTextView object which is a child object of GtkTextView. Let's define TfeTextView object which is a child object of GtkTextView.
First, look at the program below. First, look at the program below.
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type () ~~~C
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView) #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
struct _TfeTextView struct _TfeTextView
{ {
GtkTextView parent; GtkTextView parent;
GFile *file; GFile *file;
}; };
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW); G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
static void static void
tfe_text_view_init (TfeTextView *tv) { tfe_text_view_init (TfeTextView *tv) {
} }
static void static void
tfe_text_view_class_init (TfeTextViewClass *class) { tfe_text_view_class_init (TfeTextViewClass *class) {
} }
void void
tfe_text_view_set_file (TfeTextView *tv, GFile *f) { tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
tv -> file = f; tv -> file = f;
} }
GFile * GFile *
tfe_text_view_get_file (TfeTextView *tv) { tfe_text_view_get_file (TfeTextView *tv) {
return tv -> file; return tv -> file;
} }
GtkWidget * GtkWidget *
tfe_text_view_new (void) { tfe_text_view_new (void) {
return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL)); return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
} }
~~~
If you are curious about the background theory of this program, It's very good for you. If you are curious about the background theory of this program, It's very good for you.
Because to know the theory is very important for you to program GTK applications. Because to know the theory is very important for you to program GTK applications.

View file

@ -1,4 +1,4 @@
# Ui file and GtkBuiler # Ui file and GtkBuilder
## New, open and save button ## New, open and save button
@ -71,12 +71,14 @@ Those two decribe the same structure of widgets.
GtkBuilder builds widgets based on the ui file. GtkBuilder builds widgets based on the ui file.
GtkBuilder *build; ~~~C
GtkBuilder *build;
build = gtk_builder_new_from_file ("tfe3.ui"); build = gtk_builder_new_from_file ("tfe3.ui");
win = GTK_WIDGET (gtk_builder_get_object (build, "win")); win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app)); gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
nb = GTK_WIDGET (gtk_builder_get_object (build, "nb")); nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
~~~
The function `gtk_builder_new_from_file` reads the file given as an argument, build the widgets, generate GtkBuilder object and set pointers to the widgets in it. The function `gtk_builder_new_from_file` reads the file given as an argument, build the widgets, generate GtkBuilder object and set pointers to the widgets in it.
The function `gtk_builder_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file. The function `gtk_builder_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file.
@ -106,22 +108,24 @@ In the same way, you can get the source files below in the directory [src/tfe](h
GtkBuilder can build widgets using string. GtkBuilder can build widgets using string.
Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file. Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file.
char *uistring; ~~~C
char *uistring;
uistring = uistring =
"<interface>" "<interface>"
"<object class="GtkApplicationWindow" id="win">" "<object class="GtkApplicationWindow" id="win">"
"<property name=\"title\">file editor</property>" "<property name=\"title\">file editor</property>"
"<property name=\"default-width\">600</property>" "<property name=\"default-width\">600</property>"
"<property name=\"default-height\">400</property>" "<property name=\"default-height\">400</property>"
"<child>" "<child>"
"<object class=\"GtkBox\" id=\"boxv\">" "<object class=\"GtkBox\" id=\"boxv\">"
"<property name="orientation">GTK_ORIENTATION_VERTICAL</property>" "<property name="orientation">GTK_ORIENTATION_VERTICAL</property>"
... ... ... ... ... ...
... ... ... ... ... ...
"</interface>"; "</interface>";
build = gtk_builder_new_from_stringfile (uistring); build = gtk_builder_new_from_stringfile (uistring);
~~~
This method has an advantage and disadvantage. This method has an advantage and disadvantage.
The advantage is that the ui string is written in the source code. The advantage is that the ui string is written in the source code.
@ -166,12 +170,14 @@ Now run the compiler.
Then a C source file `resources.c` is generated. Then a C source file `resources.c` is generated.
Modify tfe3.c and save it as tfe3_r.c Modify tfe3.c and save it as tfe3_r.c
# include "resources.c" ~~~C
... ... ... #include "resources.c"
... ... ... ... ... ...
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui"); ... ... ...
... ... ... build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
... ... ... ... ... ...
... ... ...
~~~
Then, compile and run it. Then, compile and run it.
The window appears and it is the same as the screenshot at the beginning of this page. The window appears and it is the same as the screenshot at the beginning of this page.