mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
Use fenced code block.
This commit is contained in:
parent
26fc01e64e
commit
880dd92c82
31 changed files with 3448 additions and 3100 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
101
Rakefile
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
10
gfm/sec10.md
10
gfm/sec10.md
|
@ -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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 GtkWidget *
|
1 GtkWidget *
|
||||||
2 tfe_text_view_new (void) {
|
2 tfe_text_view_new (void) {
|
||||||
3 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
3 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||||
4 }
|
4 }
|
||||||
|
~~~
|
||||||
|
|
||||||
When this function is run, the following procedure is gone through.
|
When this function is run, the following procedure is gone through.
|
||||||
|
|
||||||
|
@ -113,6 +115,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 tfe_text_view_init (TfeTextView *tv) {
|
2 tfe_text_view_init (TfeTextView *tv) {
|
||||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
|
@ -121,6 +124,7 @@ Step four is done by the function `tfe_text_view_init`.
|
||||||
6 gtk_text_buffer_set_modified (tb, FALSE);
|
6 gtk_text_buffer_set_modified (tb, FALSE);
|
||||||
7 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
7 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||||
8 }
|
8 }
|
||||||
|
~~~
|
||||||
|
|
||||||
`tfe_text_view_init` initializes the instance.
|
`tfe_text_view_init` initializes the instance.
|
||||||
|
|
||||||
|
@ -151,6 +155,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 typedef struct _GObjectClass GObjectClass;
|
1 typedef struct _GObjectClass GObjectClass;
|
||||||
2 typedef struct _GObjectClass GInitiallyUnownedClass;
|
2 typedef struct _GObjectClass GInitiallyUnownedClass;
|
||||||
3
|
3
|
||||||
|
@ -189,6 +194,7 @@ For example, GObject class is declared in `gobject.h` in GLib source files.
|
||||||
36 /* padding */
|
36 /* padding */
|
||||||
37 gpointer pdummy[6];
|
37 gpointer pdummy[6];
|
||||||
38 };
|
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,6 +224,7 @@ 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).
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 struct _GtkWidgetClass {
|
1 struct _GtkWidgetClass {
|
||||||
2 GInitiallyUnownedClass parent_class;
|
2 GInitiallyUnownedClass parent_class;
|
||||||
3 /*< public >*/
|
3 /*< public >*/
|
||||||
|
@ -326,6 +333,7 @@ The following is extracts from the source files (not exactly the same).
|
||||||
106 GtkTextView parent_class;
|
106 GtkTextView parent_class;
|
||||||
107 } TfeTextViewClass;
|
107 } TfeTextViewClass;
|
||||||
108
|
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,6 +378,7 @@ 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`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 tfe_text_view_dispose (GObject *gobject) {
|
2 tfe_text_view_dispose (GObject *gobject) {
|
||||||
3 TfeTextView *tv = TFE_TEXT_VIEW (gobject);
|
3 TfeTextView *tv = TFE_TEXT_VIEW (gobject);
|
||||||
|
@ -379,6 +388,7 @@ You must write the code in the dispose handler `tfe_text_view_dispose`.
|
||||||
7
|
7
|
||||||
8 G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
|
8 G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
|
||||||
9 }
|
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`.
|
||||||
|
|
|
@ -55,6 +55,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 tfe_text_view_class_init (TfeTextViewClass *class) {
|
2 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||||
3 GObjectClass *object_class = G_OBJECT_CLASS (class);
|
3 GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||||
|
@ -82,6 +83,7 @@ Signal registration codes are written in the class initialization function.
|
||||||
25 1 /* n_params */,
|
25 1 /* n_params */,
|
||||||
26 param_types);
|
26 param_types);
|
||||||
27 }
|
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.
|
||||||
|
|
12
gfm/sec12.md
12
gfm/sec12.md
|
@ -9,13 +9,16 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 #include "tfetextview.h"
|
3 #include "tfetextview.h"
|
||||||
4 #include "tfenotebook.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`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||||
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||||
3
|
3
|
||||||
|
@ -45,6 +48,7 @@ Every C source files, which are `tfeapplication.c`, `tfenotebook.c` and `tfetext
|
||||||
27 GtkWidget *
|
27 GtkWidget *
|
||||||
28 tfe_text_view_new (void);
|
28 tfe_text_view_new (void);
|
||||||
29
|
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,6 +79,7 @@ If an error occures during the genration process, NULL is returned.
|
||||||
|
|
||||||
Each function is defined as follows.
|
Each function is defined as follows.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 GtkWidget *
|
1 GtkWidget *
|
||||||
2 tfe_text_view_new_with_file (GFile *file) {
|
2 tfe_text_view_new_with_file (GFile *file) {
|
||||||
3 g_return_val_if_fail (G_IS_FILE (file), NULL);
|
3 g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||||
|
@ -99,6 +104,7 @@ Each function is defined as follows.
|
||||||
22 tfe_text_view_new (void) {
|
22 tfe_text_view_new (void) {
|
||||||
23 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
23 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||||
24 }
|
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,6 +143,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
|
@ -207,6 +214,7 @@ The error is managed only in the object and no information is notified to the ca
|
||||||
68 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
68 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
||||||
69 gtk_widget_show (dialog);
|
69 gtk_widget_show (dialog);
|
||||||
70 }
|
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,6 +266,7 @@ 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`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||||
|
@ -307,6 +316,7 @@ It will be used as a transient parent window for the argument to the function `g
|
||||||
47 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
|
47 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
|
||||||
48 gtk_widget_show (dialog);
|
48 gtk_widget_show (dialog);
|
||||||
49 }
|
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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 GFile *
|
1 GFile *
|
||||||
2 tfe_text_view_get_file (TfeTextView *tv) {
|
2 tfe_text_view_get_file (TfeTextView *tv) {
|
||||||
3 g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
|
3 g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
|
||||||
4
|
4
|
||||||
5 return g_file_dup (tv->file);
|
5 return g_file_dup (tv->file);
|
||||||
6 }
|
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.
|
||||||
|
|
12
gfm/sec13.md
12
gfm/sec13.md
|
@ -6,6 +6,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 void
|
1 void
|
||||||
2 notebook_page_save(GtkNotebook *nb);
|
2 notebook_page_save(GtkNotebook *nb);
|
||||||
3
|
3
|
||||||
|
@ -18,6 +19,7 @@ It connects the application and TfeTextView objects.
|
||||||
10 void
|
10 void
|
||||||
11 notebook_page_new (GtkNotebook *nb);
|
11 notebook_page_new (GtkNotebook *nb);
|
||||||
12
|
12
|
||||||
|
~~~
|
||||||
|
|
||||||
This header file shows the public functions in `tfenotebook.c`.
|
This header file shows the public functions in `tfenotebook.c`.
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ Now let's look at each program of the functions.
|
||||||
|
|
||||||
## notebook\_page\_new
|
## notebook\_page\_new
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static gchar*
|
1 static gchar*
|
||||||
2 get_untitled () {
|
2 get_untitled () {
|
||||||
3 static int c = -1;
|
3 static int c = -1;
|
||||||
|
@ -81,6 +84,7 @@ Now let's look at each program of the functions.
|
||||||
35 filename = get_untitled ();
|
35 filename = get_untitled ();
|
||||||
36 notebook_page_build (nb, tv, filename);
|
36 notebook_page_build (nb, tv, filename);
|
||||||
37 }
|
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,6 +106,7 @@ 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
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 void
|
1 void
|
||||||
2 notebook_page_new_with_file (GtkNotebook *nb, GFile *file) {
|
2 notebook_page_new_with_file (GtkNotebook *nb, GFile *file) {
|
||||||
3 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
3 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||||
|
@ -115,6 +120,7 @@ The caller of `get_untitled` is in charge of freeing the memories of the string.
|
||||||
11 filename = g_file_get_basename (file);
|
11 filename = g_file_get_basename (file);
|
||||||
12 notebook_page_build (nb, tv, filename);
|
12 notebook_page_build (nb, tv, filename);
|
||||||
13 }
|
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,6 +128,7 @@ If it returns NULL, then do nothing and return because of an error.
|
||||||
|
|
||||||
## notebook\_page\_open
|
## notebook\_page\_open
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 open_response (TfeTextView *tv, gint response, GtkNotebook *nb) {
|
2 open_response (TfeTextView *tv, gint response, GtkNotebook *nb) {
|
||||||
3 GFile *file;
|
3 GFile *file;
|
||||||
|
@ -150,6 +157,7 @@ If it returns NULL, then do nothing and return because of an error.
|
||||||
26 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
26 g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);
|
||||||
27 tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
27 tfe_text_view_open (TFE_TEXT_VIEW (tv), gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW));
|
||||||
28 }
|
28 }
|
||||||
|
~~~
|
||||||
|
|
||||||
- 19-28: `notebook_page_open` function.
|
- 19-28: `notebook_page_open` function.
|
||||||
- 25: Generate TfeTextView object.
|
- 25: Generate TfeTextView object.
|
||||||
|
@ -169,6 +177,7 @@ Get the filename, build the contents of the page.
|
||||||
|
|
||||||
## notebook\_page\_save
|
## notebook\_page\_save
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 void
|
1 void
|
||||||
2 notebook_page_save(GtkNotebook *nb) {
|
2 notebook_page_save(GtkNotebook *nb) {
|
||||||
3 gint i;
|
3 gint i;
|
||||||
|
@ -180,6 +189,7 @@ Get the filename, build the contents of the page.
|
||||||
9 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
9 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||||
10 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
10 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||||
11 }
|
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,6 +200,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 file_changed (TfeTextView *tv, GtkNotebook *nb) {
|
2 file_changed (TfeTextView *tv, GtkNotebook *nb) {
|
||||||
3 GFile *file;
|
3 GFile *file;
|
||||||
|
@ -208,6 +219,7 @@ This handler changes the label of GtkNotebookPage.
|
||||||
16 g_object_unref (file);
|
16 g_object_unref (file);
|
||||||
17 g_free (filename);
|
17 g_free (filename);
|
||||||
18 }
|
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`.
|
||||||
|
|
10
gfm/sec14.md
10
gfm/sec14.md
|
@ -15,6 +15,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 int
|
1 int
|
||||||
2 main (int argc, char **argv) {
|
2 main (int argc, char **argv) {
|
||||||
3 GtkApplication *app;
|
3 GtkApplication *app;
|
||||||
|
@ -30,6 +31,7 @@ It connects the command line given by the user and GTK application.
|
||||||
13 g_object_unref (app);
|
13 g_object_unref (app);
|
||||||
14 return stat;
|
14 return stat;
|
||||||
15 }
|
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,6 +49,7 @@ What the signal handler needs to do is initialization of the application.
|
||||||
|
|
||||||
The handler is as follows.
|
The handler is as follows.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 tfe_startup (GApplication *application) {
|
2 tfe_startup (GApplication *application) {
|
||||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||||
|
@ -79,6 +82,7 @@ The handler is as follows.
|
||||||
30 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
30 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||||
31 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
31 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
32 }
|
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,6 +172,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 tfe_activate (GApplication *application) {
|
2 tfe_activate (GApplication *application) {
|
||||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||||
|
@ -201,6 +206,7 @@ They just generate a new GtkNotebookPage.
|
||||||
31 notebook_page_new (nb);
|
31 notebook_page_new (nb);
|
||||||
32 gtk_widget_show (win);
|
32 gtk_widget_show (win);
|
||||||
33 }
|
33 }
|
||||||
|
~~~
|
||||||
|
|
||||||
- 1-14: `tfe_activate`.
|
- 1-14: `tfe_activate`.
|
||||||
- 8-10: Get GtkNotebook object.
|
- 8-10: Get GtkNotebook object.
|
||||||
|
@ -249,6 +255,7 @@ 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
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 open_clicked (GtkWidget *btno, GtkNotebook *nb) {
|
2 open_clicked (GtkWidget *btno, GtkNotebook *nb) {
|
||||||
3 notebook_page_open (nb);
|
3 notebook_page_open (nb);
|
||||||
|
@ -279,6 +286,7 @@ The second instance immediately quits so shell prompt soon appears.
|
||||||
28 gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
|
28 gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
|
||||||
29 }
|
29 }
|
||||||
30 }
|
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,6 +297,7 @@ First, get the top level window and call `gtk_window_destroy`.
|
||||||
|
|
||||||
## meson.build
|
## meson.build
|
||||||
|
|
||||||
|
~~~meson
|
||||||
1 project('tfe', 'c')
|
1 project('tfe', 'c')
|
||||||
2
|
2
|
||||||
3 gtkdep = dependency('gtk4')
|
3 gtkdep = dependency('gtk4')
|
||||||
|
@ -299,6 +308,7 @@ First, get the top level window and call `gtk_window_destroy`.
|
||||||
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
|
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
|
||||||
9
|
9
|
||||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
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.
|
||||||
|
|
||||||
|
|
18
gfm/sec15.md
18
gfm/sec15.md
|
@ -33,6 +33,7 @@ It is a good practice for you to add more features.
|
||||||
|
|
||||||
## meson.buld
|
## meson.buld
|
||||||
|
|
||||||
|
~~~meson
|
||||||
1 project('tfe', 'c')
|
1 project('tfe', 'c')
|
||||||
2
|
2
|
||||||
3 gtkdep = dependency('gtk4')
|
3 gtkdep = dependency('gtk4')
|
||||||
|
@ -43,18 +44,22 @@ It is a good practice for you to add more features.
|
||||||
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
|
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
|
||||||
9
|
9
|
||||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfe.gresource.xml
|
## tfe.gresource.xml
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
2 <gresources>
|
2 <gresources>
|
||||||
3 <gresource prefix="/com/github/ToshioCP/tfe">
|
3 <gresource prefix="/com/github/ToshioCP/tfe">
|
||||||
4 <file>tfe.ui</file>
|
4 <file>tfe.ui</file>
|
||||||
5 </gresource>
|
5 </gresource>
|
||||||
6 </gresources>
|
6 </gresources>
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfe.ui
|
## tfe.ui
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <interface>
|
1 <interface>
|
||||||
2 <object class="GtkApplicationWindow" id="win">
|
2 <object class="GtkApplicationWindow" id="win">
|
||||||
3 <property name="title">file editor</property>
|
3 <property name="title">file editor</property>
|
||||||
|
@ -119,16 +124,20 @@ It is a good practice for you to add more features.
|
||||||
62 </object>
|
62 </object>
|
||||||
63 </interface>
|
63 </interface>
|
||||||
64
|
64
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfe.h
|
## tfe.h
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 #include "tfetextview.h"
|
3 #include "tfetextview.h"
|
||||||
4 #include "tfenotebook.h"
|
4 #include "tfenotebook.h"
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfeapplication.c
|
## tfeapplication.c
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include "tfe.h"
|
1 #include "tfe.h"
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -246,9 +255,11 @@ It is a good practice for you to add more features.
|
||||||
115 return stat;
|
115 return stat;
|
||||||
116 }
|
116 }
|
||||||
117
|
117
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfenotebook.h
|
## tfenotebook.h
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 void
|
1 void
|
||||||
2 notebook_page_save(GtkNotebook *nb);
|
2 notebook_page_save(GtkNotebook *nb);
|
||||||
3
|
3
|
||||||
|
@ -261,9 +272,11 @@ It is a good practice for you to add more features.
|
||||||
10 void
|
10 void
|
||||||
11 notebook_page_new (GtkNotebook *nb);
|
11 notebook_page_new (GtkNotebook *nb);
|
||||||
12
|
12
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfenotebook.c
|
## tfenotebook.c
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include "tfe.h"
|
1 #include "tfe.h"
|
||||||
2
|
2
|
||||||
3 /* The returned string should be freed with g_free() when no longer needed. */
|
3 /* The returned string should be freed with g_free() when no longer needed. */
|
||||||
|
@ -380,9 +393,11 @@ It is a good practice for you to add more features.
|
||||||
114 notebook_page_build (nb, tv, filename);
|
114 notebook_page_build (nb, tv, filename);
|
||||||
115 }
|
115 }
|
||||||
116
|
116
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfetextview.h
|
## tfetextview.h
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||||
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||||
3
|
3
|
||||||
|
@ -412,9 +427,11 @@ It is a good practice for you to add more features.
|
||||||
27 GtkWidget *
|
27 GtkWidget *
|
||||||
28 tfe_text_view_new (void);
|
28 tfe_text_view_new (void);
|
||||||
29
|
29
|
||||||
|
~~~
|
||||||
|
|
||||||
## tfetextview.c
|
## tfetextview.c
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include "tfe.h"
|
1 #include "tfe.h"
|
||||||
2
|
2
|
||||||
3 struct _TfeTextView
|
3 struct _TfeTextView
|
||||||
|
@ -633,6 +650,7 @@ It is a good practice for you to add more features.
|
||||||
216 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
216 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||||
217 }
|
217 }
|
||||||
218
|
218
|
||||||
|
~~~
|
||||||
|
|
||||||
## Total number of lines, words and charcters
|
## Total number of lines, words and charcters
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -166,6 +167,7 @@ The following is a simple example of menus and actions.
|
||||||
45 return stat;
|
45 return stat;
|
||||||
46 }
|
46 }
|
||||||
47
|
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.
|
||||||
|
|
13
gfm/sec17.md
13
gfm/sec17.md
|
@ -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,6 +190,7 @@ 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".
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <glib.h>
|
1 #include <glib.h>
|
||||||
2
|
2
|
||||||
3 int
|
3 int
|
||||||
|
@ -195,6 +199,7 @@ It finally output the string "s".
|
||||||
6 const gchar *type_string = g_variant_type_peek_string (vtype);
|
6 const gchar *type_string = g_variant_type_peek_string (vtype);
|
||||||
7 g_print ("%s\n",type_string);
|
7 g_print ("%s\n",type_string);
|
||||||
8 }
|
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,6 +222,7 @@ And the radio button of the selected menu turns on.
|
||||||
|
|
||||||
The code is as follows.
|
The code is as follows.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static GtkCssProvider *provider;
|
3 static GtkCssProvider *provider;
|
||||||
|
@ -322,6 +328,7 @@ The code is as follows.
|
||||||
103 return stat;
|
103 return stat;
|
||||||
104 }
|
104 }
|
||||||
105
|
105
|
||||||
|
~~~
|
||||||
|
|
||||||
- 5-26: Signal handlers.
|
- 5-26: Signal handlers.
|
||||||
They have been explained in this section.
|
They have been explained in this section.
|
||||||
|
|
51
gfm/sec18.md
51
gfm/sec18.md
|
@ -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,15 +13,18 @@ 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
<interface>
|
<interface>
|
||||||
<menu id="menubar">
|
<menu id="menubar">
|
||||||
</menu>
|
</menu>
|
||||||
</interface>
|
</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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
<submenu>
|
<submenu>
|
||||||
<attribute name="label">File</attribute>
|
<attribute name="label">File</attribute>
|
||||||
<item>
|
<item>
|
||||||
|
@ -29,6 +32,7 @@ It will be refered by GtkBuilder.
|
||||||
<attribute name="action">win.new</attribute>
|
<attribute name="action">win.new</attribute>
|
||||||
</item>
|
</item>
|
||||||
</submenu>
|
</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,6 +44,7 @@ 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label">File</attribute>
|
<attribute name="label">File</attribute>
|
||||||
<link name="submenu">
|
<link name="submenu">
|
||||||
|
@ -49,6 +54,7 @@ The ui file above can be described as follows.
|
||||||
</item>
|
</item>
|
||||||
</link>
|
</link>
|
||||||
</item>
|
</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,6 +69,7 @@ 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`.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
2 <interface>
|
2 <interface>
|
||||||
3 <menu id="menubar">
|
3 <menu id="menubar">
|
||||||
|
@ -135,23 +142,28 @@ The following is the ui file of the menu in `menu3`.
|
||||||
70 </submenu>
|
70 </submenu>
|
||||||
71 </menu>
|
71 </menu>
|
||||||
72 </interface>
|
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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
2 <gresources>
|
2 <gresources>
|
||||||
3 <gresource prefix="/com/github/ToshioCP/menu3">
|
3 <gresource prefix="/com/github/ToshioCP/menu3">
|
||||||
4 <file>menu3.ui</file>
|
4 <file>menu3.ui</file>
|
||||||
5 </gresource>
|
5 </gresource>
|
||||||
6 </gresources>
|
6 </gresources>
|
||||||
|
~~~
|
||||||
|
|
||||||
GtkBuilder builds menus from the resource.
|
GtkBuilder builds menus from the resource.
|
||||||
|
|
||||||
|
~~~C
|
||||||
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
typedef struct _GActionEntry GActionEntry;
|
typedef struct _GActionEntry GActionEntry;
|
||||||
|
|
||||||
struct _GActionEntry
|
struct _GActionEntry
|
||||||
{
|
{
|
||||||
const gchar *name; /* action name */
|
/* action name */
|
||||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data); /* activate handler */
|
const gchar *name;
|
||||||
const gchar *parameter_type; /* the type of the parameter given as a single GVariant type string */
|
/* activate handler */
|
||||||
const gchar *state; /* initial state given in GVariant text format */
|
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
|
||||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data); /* change-state handler */
|
/* 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 >*/
|
/*< private >*/
|
||||||
gsize padding[3];
|
gsize padding[3];
|
||||||
};
|
};
|
||||||
|
~~~
|
||||||
For example, the actions in the previous section are:
|
For example, the actions in the previous section are:
|
||||||
|
|
||||||
|
~~~C
|
||||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||||
{ "color", color_activated, "s", "red", NULL }
|
{ "color", color_activated, "s", "red", NULL }
|
||||||
{ "quit", quit_activated, NULL, NULL, 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
const GActionEntry app_entries[] = {
|
const GActionEntry app_entries[] = {
|
||||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
{ "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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
const GActionEntry win_entries[] = {
|
const GActionEntry win_entries[] = {
|
||||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||||
{ "color", color_activated, "s", "red", NULL }
|
{ "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,6 +242,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -323,9 +349,11 @@ The C source code of `menu3` and `meson.build` is as follows.
|
||||||
104 return stat;
|
104 return stat;
|
||||||
105 }
|
105 }
|
||||||
106
|
106
|
||||||
|
~~~
|
||||||
|
|
||||||
meson.build
|
meson.build
|
||||||
|
|
||||||
|
~~~meson
|
||||||
1 project('menu3', 'c')
|
1 project('menu3', 'c')
|
||||||
2
|
2
|
||||||
3 gtkdep = dependency('gtk4')
|
3 gtkdep = dependency('gtk4')
|
||||||
|
@ -336,6 +364,7 @@ meson.build
|
||||||
8 sourcefiles=files('menu3.c')
|
8 sourcefiles=files('menu3.c')
|
||||||
9
|
9
|
||||||
10 executable('menu3', sourcefiles, resources, dependencies: gtkdep)
|
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)
|
||||||
|
|
|
@ -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,6 +46,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <cairo.h>
|
1 #include <cairo.h>
|
||||||
2
|
2
|
||||||
3 int
|
3 int
|
||||||
|
@ -77,6 +78,7 @@ Here's a simple example code that draws a small square and save it as a png file
|
||||||
29
|
29
|
||||||
30 return 0;
|
30 return 0;
|
||||||
31 }
|
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,6 +119,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -156,6 +159,7 @@ The following is a very simple example.
|
||||||
37 return stat;
|
37 return stat;
|
||||||
38 }
|
38 }
|
||||||
39
|
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)
|
||||||
|
|
|
@ -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/"
|
||||||
|
|
10
gfm/sec20.md
10
gfm/sec20.md
|
@ -34,6 +34,7 @@ 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <interface>
|
1 <interface>
|
||||||
2 <object class="GtkApplicationWindow" id="win">
|
2 <object class="GtkApplicationWindow" id="win">
|
||||||
3 <property name="title">color changer</property>
|
3 <property name="title">color changer</property>
|
||||||
|
@ -115,6 +116,7 @@ The ui file is as follows.
|
||||||
79 </object>
|
79 </object>
|
||||||
80 </interface>
|
80 </interface>
|
||||||
81
|
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".
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
2 <gresources>
|
2 <gresources>
|
||||||
3 <gresource prefix="/com/github/ToshioCP/color">
|
3 <gresource prefix="/com/github/ToshioCP/color">
|
||||||
4 <file>color.ui</file>
|
4 <file>color.ui</file>
|
||||||
5 </gresource>
|
5 </gresource>
|
||||||
6 </gresources>
|
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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 #include "tfetextview.h"
|
3 #include "tfetextview.h"
|
||||||
|
~~~
|
||||||
|
|
||||||
# Colorapplication.c
|
# Colorapplication.c
|
||||||
|
|
||||||
|
@ -169,6 +175,7 @@ Particularly, `Run` signal handler is the point in this program.
|
||||||
|
|
||||||
The following is `colorapplication.c`.
|
The following is `colorapplication.c`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include "color.h"
|
1 #include "color.h"
|
||||||
2
|
2
|
||||||
3 static GtkWidget *win;
|
3 static GtkWidget *win;
|
||||||
|
@ -291,6 +298,7 @@ The following is `colorapplication.c`.
|
||||||
120 return stat;
|
120 return stat;
|
||||||
121 }
|
121 }
|
||||||
122
|
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,6 +340,7 @@ 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.
|
||||||
|
|
||||||
|
~~~meson
|
||||||
1 project('color', 'c')
|
1 project('color', 'c')
|
||||||
2
|
2
|
||||||
3 gtkdep = dependency('gtk4')
|
3 gtkdep = dependency('gtk4')
|
||||||
|
@ -342,6 +351,7 @@ An argument "export_dynamic: true" is added to executable function.
|
||||||
8 sourcefiles=files('colorapplication.c', 'tfetextview.c')
|
8 sourcefiles=files('colorapplication.c', 'tfetextview.c')
|
||||||
9
|
9
|
||||||
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
||||||
|
~~~
|
||||||
|
|
||||||
# Compile and execute it
|
# Compile and execute it
|
||||||
|
|
||||||
|
|
12
gfm/sec3.md
12
gfm/sec3.md
|
@ -20,6 +20,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 int
|
3 int
|
||||||
|
@ -33,6 +34,7 @@ The following is the C code representing the scenario above.
|
||||||
11 return stat;
|
11 return stat;
|
||||||
12 }
|
12 }
|
||||||
13
|
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,6 +101,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -116,6 +121,7 @@ We use a function `g_signal_connect` which connects a signal to a handler.
|
||||||
17 return stat;
|
17 return stat;
|
||||||
18 }
|
18 }
|
||||||
19
|
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,6 +191,7 @@ Now rewrite the function `on_activate`.
|
||||||
|
|
||||||
#### Generate a GtkWindow
|
#### Generate a GtkWindow
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 on_activate (GApplication *app, gpointer user_data) {
|
2 on_activate (GApplication *app, gpointer user_data) {
|
||||||
3 GtkWidget *win;
|
3 GtkWidget *win;
|
||||||
|
@ -193,6 +200,7 @@ Now rewrite the function `on_activate`.
|
||||||
6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||||
7 gtk_widget_show (win);
|
7 gtk_widget_show (win);
|
||||||
8 }
|
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,6 +273,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 on_activate (GApplication *app, gpointer user_data) {
|
2 on_activate (GApplication *app, gpointer user_data) {
|
||||||
3 GtkWidget *win;
|
3 GtkWidget *win;
|
||||||
|
@ -274,6 +283,7 @@ Now rewrite the program and use GtkAppliction Window.
|
||||||
7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||||
8 gtk_widget_show (win);
|
8 gtk_widget_show (win);
|
||||||
9 }
|
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.
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -40,6 +41,7 @@ It is a widget with a string in it.
|
||||||
27 return stat;
|
27 return stat;
|
||||||
28 }
|
28 }
|
||||||
29
|
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,6 +102,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -135,6 +138,7 @@ The following program shows how to catch the signal and do something.
|
||||||
33 return stat;
|
33 return stat;
|
||||||
34 }
|
34 }
|
||||||
35
|
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,6 +161,7 @@ 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`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 click_cb (GtkButton *btn, gpointer user_data) {
|
2 click_cb (GtkButton *btn, gpointer user_data) {
|
||||||
3 GtkWindow *win = GTK_WINDOW (user_data);
|
3 GtkWindow *win = GTK_WINDOW (user_data);
|
||||||
|
@ -178,6 +183,7 @@ The following code is `lb3.c`.
|
||||||
19
|
19
|
||||||
20 gtk_widget_show (win);
|
20 gtk_widget_show (win);
|
||||||
21 }
|
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,6 +243,7 @@ After this, the Widgets are connected as following diagram.
|
||||||
|
|
||||||
Now, code it.
|
Now, code it.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -294,6 +301,7 @@ Now, code it.
|
||||||
55 g_object_unref (app);
|
55 g_object_unref (app);
|
||||||
56 return stat;
|
56 return stat;
|
||||||
57 }
|
57 }
|
||||||
|
~~~
|
||||||
|
|
||||||
Look at the function `on_activate`.
|
Look at the function `on_activate`.
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -56,6 +57,7 @@ See a sample program `tfv1.c` below.
|
||||||
44 return stat;
|
44 return stat;
|
||||||
45 }
|
45 }
|
||||||
46
|
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,6 +110,7 @@ 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`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -158,6 +161,7 @@ Though you can modify the source file by this diff output, It's good for you to
|
||||||
48 return stat;
|
48 return stat;
|
||||||
49 }
|
49 }
|
||||||
50
|
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.
|
||||||
|
|
|
@ -89,6 +89,7 @@ It works as follows.
|
||||||
|
|
||||||
The program is as follows.
|
The program is as follows.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -145,6 +146,7 @@ The program is as follows.
|
||||||
54 return stat;
|
54 return stat;
|
||||||
55 }
|
55 }
|
||||||
56
|
56
|
||||||
|
~~~
|
||||||
|
|
||||||
Save it as `tfv3.c`.
|
Save it as `tfv3.c`.
|
||||||
Then compile and run it.
|
Then compile and run it.
|
||||||
|
@ -211,6 +213,7 @@ 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`.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 static void
|
3 static void
|
||||||
|
@ -282,6 +285,7 @@ Now I want to show you the program `tfv4.c`.
|
||||||
69 return stat;
|
69 return stat;
|
||||||
70 }
|
70 }
|
||||||
71
|
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.
|
||||||
|
|
|
@ -57,6 +57,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||||
|
|
||||||
|
@ -90,6 +91,7 @@ First, look at the program below.
|
||||||
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,6 +159,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static gboolean
|
1 static gboolean
|
||||||
2 before_close (GtkWindow *win, GtkWidget *nb) {
|
2 before_close (GtkWindow *win, GtkWidget *nb) {
|
||||||
3 GtkWidget *scr;
|
3 GtkWidget *scr;
|
||||||
|
@ -182,6 +185,7 @@ The program of before\_close is as follows.
|
||||||
23 }
|
23 }
|
||||||
24 return FALSE;
|
24 return FALSE;
|
||||||
25 }
|
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,6 +199,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 /* Define TfeTextView Widget which is the child object of GtkTextView */
|
3 /* Define TfeTextView Widget which is the child object of GtkTextView */
|
||||||
|
@ -331,6 +336,7 @@ Now I will show you all the source code of `tfe1`.c.
|
||||||
134 return stat;
|
134 return stat;
|
||||||
135 }
|
135 }
|
||||||
136
|
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.
|
||||||
|
|
16
gfm/sec8.md
16
gfm/sec8.md
|
@ -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,6 +16,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||||
3 GtkWidget *win;
|
3 GtkWidget *win;
|
||||||
|
@ -102,6 +103,7 @@ The function `on_open` in the source code `tfe2.c` is as follows.
|
||||||
84 } else
|
84 } else
|
||||||
85 gtk_window_destroy (GTK_WINDOW (win));
|
85 gtk_window_destroy (GTK_WINDOW (win));
|
||||||
86 }
|
86 }
|
||||||
|
~~~
|
||||||
|
|
||||||
The point is how to build the window.
|
The point is how to build the window.
|
||||||
|
|
||||||
|
@ -135,6 +137,7 @@ 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <interface>
|
1 <interface>
|
||||||
2 <object class="GtkApplicationWindow" id="win">
|
2 <object class="GtkApplicationWindow" id="win">
|
||||||
3 <property name="title">file editor</property>
|
3 <property name="title">file editor</property>
|
||||||
|
@ -194,6 +197,7 @@ First, let's look at the ui file `tfe3.ui` that defines a structure of the widge
|
||||||
57 </object>
|
57 </object>
|
||||||
58 </interface>
|
58 </interface>
|
||||||
59
|
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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
GtkBuilder *build;
|
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,6 +301,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 static void
|
1 static void
|
||||||
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||||
3 GtkWidget *win;
|
3 GtkWidget *win;
|
||||||
|
@ -343,6 +350,7 @@ Only functions `on_open` are shown as follows.
|
||||||
46 } else
|
46 } else
|
||||||
47 gtk_window_destroy (GTK_WINDOW (win));
|
47 gtk_window_destroy (GTK_WINDOW (win));
|
||||||
48 }
|
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,6 +361,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
char *uistring;
|
char *uistring;
|
||||||
|
|
||||||
uistring =
|
uistring =
|
||||||
|
@ -369,6 +378,7 @@ Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_f
|
||||||
"</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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
2 <gresources>
|
2 <gresources>
|
||||||
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
||||||
4 <file>tfe3.ui</file>
|
4 <file>tfe3.ui</file>
|
||||||
5 </gresource>
|
5 </gresource>
|
||||||
6 </gresources>
|
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
|
||||||
|
|
||||||
|
~~~C
|
||||||
#include "resources.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.
|
||||||
|
|
16
gfm/sec9.md
16
gfm/sec9.md
|
@ -42,6 +42,7 @@ All the source files are listed below.
|
||||||
|
|
||||||
`tfetextview.h`
|
`tfetextview.h`
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2
|
2
|
||||||
3 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
3 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||||
|
@ -56,9 +57,11 @@ All the source files are listed below.
|
||||||
12 GtkWidget *
|
12 GtkWidget *
|
||||||
13 tfe_text_view_new (void);
|
13 tfe_text_view_new (void);
|
||||||
14
|
14
|
||||||
|
~~~
|
||||||
|
|
||||||
`tfetextview.c`
|
`tfetextview.c`
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2 #include "tfetextview.h"
|
2 #include "tfetextview.h"
|
||||||
3
|
3
|
||||||
|
@ -93,9 +96,11 @@ All the source files are listed below.
|
||||||
32 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
32 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||||
33 }
|
33 }
|
||||||
34
|
34
|
||||||
|
~~~
|
||||||
|
|
||||||
`tfe.c`
|
`tfe.c`
|
||||||
|
|
||||||
|
~~~C
|
||||||
1 #include <gtk/gtk.h>
|
1 #include <gtk/gtk.h>
|
||||||
2 #include "tfetextview.h"
|
2 #include "tfetextview.h"
|
||||||
3
|
3
|
||||||
|
@ -166,9 +171,11 @@ All the source files are listed below.
|
||||||
68 return stat;
|
68 return stat;
|
||||||
69 }
|
69 }
|
||||||
70
|
70
|
||||||
|
~~~
|
||||||
|
|
||||||
`tfe.ui`
|
`tfe.ui`
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <interface>
|
1 <interface>
|
||||||
2 <object class="GtkApplicationWindow" id="win">
|
2 <object class="GtkApplicationWindow" id="win">
|
||||||
3 <property name="title">file editor</property>
|
3 <property name="title">file editor</property>
|
||||||
|
@ -228,15 +235,18 @@ All the source files are listed below.
|
||||||
57 </object>
|
57 </object>
|
||||||
58 </interface>
|
58 </interface>
|
||||||
59
|
59
|
||||||
|
~~~
|
||||||
|
|
||||||
`tfe.gresource.xml`
|
`tfe.gresource.xml`
|
||||||
|
|
||||||
|
~~~xml
|
||||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||||
2 <gresources>
|
2 <gresources>
|
||||||
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
||||||
4 <file>tfe.ui</file>
|
4 <file>tfe.ui</file>
|
||||||
5 </gresource>
|
5 </gresource>
|
||||||
6 </gresources>
|
6 </gresources>
|
||||||
|
~~~
|
||||||
|
|
||||||
## Make
|
## Make
|
||||||
|
|
||||||
|
@ -278,6 +288,7 @@ 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.
|
||||||
|
|
||||||
|
~~~makefile
|
||||||
1 all: tfe
|
1 all: tfe
|
||||||
2
|
2
|
||||||
3 tfe: tfe.o tfetextview.o resources.o
|
3 tfe: tfe.o tfetextview.o resources.o
|
||||||
|
@ -297,6 +308,7 @@ The Makefile for `tfe` is as follows.
|
||||||
17
|
17
|
||||||
18 clean:
|
18 clean:
|
||||||
19 rm -f tfe tfe.o tfetextview.o resources.o resources.c
|
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,6 +336,7 @@ 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.
|
||||||
|
|
||||||
|
~~~ruby
|
||||||
1 require 'rake/clean'
|
1 require 'rake/clean'
|
||||||
2
|
2
|
||||||
3 targetfile = "tfe"
|
3 targetfile = "tfe"
|
||||||
|
@ -349,6 +362,7 @@ Rake has task and file task, which is similar to target, prerequisite and recipe
|
||||||
23 file rscfile => ["tfe.gresource.xml", "tfe.ui"] do |t|
|
23 file rscfile => ["tfe.gresource.xml", "tfe.ui"] do |t|
|
||||||
24 sh "glib-compile-resources #{t.prerequisites[0]} --target=#{t.name} --generate-source"
|
24 sh "glib-compile-resources #{t.prerequisites[0]} --target=#{t.name} --generate-source"
|
||||||
25 end
|
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,6 +394,7 @@ 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.
|
||||||
|
|
||||||
|
~~~meson
|
||||||
1 project('tfe', 'c')
|
1 project('tfe', 'c')
|
||||||
2
|
2
|
||||||
3 gtkdep = dependency('gtk4')
|
3 gtkdep = dependency('gtk4')
|
||||||
|
@ -390,6 +405,7 @@ To use meson, you first need to write `meson.build` file.
|
||||||
8 sourcefiles=files('tfe.c', 'tfetextview.c')
|
8 sourcefiles=files('tfe.c', 'tfetextview.c')
|
||||||
9
|
9
|
||||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
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.
|
||||||
|
|
|
@ -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
|
|
||||||
elsif type == "latex"
|
|
||||||
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
|
md_buf << line
|
||||||
end
|
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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -11,15 +11,18 @@ 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
<interface>
|
<interface>
|
||||||
<menu id="menubar">
|
<menu id="menubar">
|
||||||
</menu>
|
</menu>
|
||||||
</interface>
|
</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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
<submenu>
|
<submenu>
|
||||||
<attribute name="label">File</attribute>
|
<attribute name="label">File</attribute>
|
||||||
<item>
|
<item>
|
||||||
|
@ -27,6 +30,7 @@ It will be refered by GtkBuilder.
|
||||||
<attribute name="action">win.new</attribute>
|
<attribute name="action">win.new</attribute>
|
||||||
</item>
|
</item>
|
||||||
</submenu>
|
</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,6 +42,7 @@ 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.
|
||||||
|
|
||||||
|
~~~xml
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label">File</attribute>
|
<attribute name="label">File</attribute>
|
||||||
<link name="submenu">
|
<link name="submenu">
|
||||||
|
@ -47,6 +52,7 @@ The ui file above can be described as follows.
|
||||||
</item>
|
</item>
|
||||||
</link>
|
</link>
|
||||||
</item>
|
</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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
typedef struct _GActionEntry GActionEntry;
|
typedef struct _GActionEntry GActionEntry;
|
||||||
|
|
||||||
struct _GActionEntry
|
struct _GActionEntry
|
||||||
{
|
{
|
||||||
const gchar *name; /* action name */
|
/* action name */
|
||||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data); /* activate handler */
|
const gchar *name;
|
||||||
const gchar *parameter_type; /* the type of the parameter given as a single GVariant type string */
|
/* activate handler */
|
||||||
const gchar *state; /* initial state given in GVariant text format */
|
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
|
||||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data); /* change-state handler */
|
/* 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 >*/
|
/*< private >*/
|
||||||
gsize padding[3];
|
gsize padding[3];
|
||||||
};
|
};
|
||||||
|
~~~
|
||||||
For example, the actions in the previous section are:
|
For example, the actions in the previous section are:
|
||||||
|
|
||||||
|
~~~C
|
||||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||||
{ "color", color_activated, "s", "red", NULL }
|
{ "color", color_activated, "s", "red", NULL }
|
||||||
{ "quit", quit_activated, NULL, NULL, 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
const GActionEntry app_entries[] = {
|
const GActionEntry app_entries[] = {
|
||||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
{ "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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
const GActionEntry win_entries[] = {
|
const GActionEntry win_entries[] = {
|
||||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||||
{ "color", color_activated, "s", "red", NULL }
|
{ "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.
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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/"
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -55,6 +55,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@ First, look at the program below.
|
||||||
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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
GtkBuilder *build;
|
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,6 +108,7 @@ 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.
|
||||||
|
|
||||||
|
~~~C
|
||||||
char *uistring;
|
char *uistring;
|
||||||
|
|
||||||
uistring =
|
uistring =
|
||||||
|
@ -122,6 +125,7 @@ Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_f
|
||||||
"</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
|
||||||
|
|
||||||
|
~~~C
|
||||||
#include "resources.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.
|
||||||
|
|
Loading…
Reference in a new issue