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/menu/a.out
|
||||
src/color/_build
|
||||
src/turtle
|
||||
|
||||
html/*
|
||||
latex/*
|
||||
|
|
101
Rakefile
101
Rakefile
|
@ -156,12 +156,105 @@ EOS
|
|||
main.gsub!(/@@@ abstract\n/, abstract_latex)
|
||||
|
||||
helper = <<'EOS'
|
||||
\usepackage[pdftex]{graphicx}
|
||||
\usepackage[colorlinks=true,linkcolor=black]{hyperref}
|
||||
\usepackage[margin=2.4cm]{geometry}
|
||||
\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}{%
|
||||
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
|
||||
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
|
||||
|
||||
\author{}
|
||||
\date{}
|
||||
EOS
|
||||
# tasks
|
||||
|
||||
|
@ -262,7 +355,7 @@ end
|
|||
|
||||
0.upto(srcfiles.size - 1) do |i|
|
||||
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}"
|
||||
File.delete("latex/#{srcfiles[i].to_md}")
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ You can read it without download.
|
|||
1. [Widgets (2)](gfm/sec5.md)
|
||||
1. [Widgets (3)](gfm/sec6.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. [Instance and class](gfm/sec10.md)
|
||||
1. [Signals](gfm/sec11.md)
|
||||
|
|
344
gfm/sec10.md
344
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.
|
||||
|
||||
1 GtkWidget *
|
||||
2 tfe_text_view_new (void) {
|
||||
3 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
4 }
|
||||
~~~C
|
||||
1 GtkWidget *
|
||||
2 tfe_text_view_new (void) {
|
||||
3 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
4 }
|
||||
~~~
|
||||
|
||||
When this function is run, the following procedure is gone through.
|
||||
|
||||
|
@ -113,14 +115,16 @@ Step four is done by the function `tfe_text_view_init`.
|
|||
> In the same way, `gtk_text_view_init`, `gtk_widget_init` and `g_object_init` is the initialization functions of GtkTextView, GtkWidget and GObject respectively.
|
||||
> You can find them in the GTK or GLib source files.
|
||||
|
||||
1 static void
|
||||
2 tfe_text_view_init (TfeTextView *tv) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4
|
||||
5 tv->file = NULL;
|
||||
6 gtk_text_buffer_set_modified (tb, FALSE);
|
||||
7 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
8 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 tfe_text_view_init (TfeTextView *tv) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4
|
||||
5 tv->file = NULL;
|
||||
6 gtk_text_buffer_set_modified (tb, FALSE);
|
||||
7 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
8 }
|
||||
~~~
|
||||
|
||||
`tfe_text_view_init` initializes the instance.
|
||||
|
||||
|
@ -151,44 +155,46 @@ Class comprises mainly pointers to functions.
|
|||
Those functions are used by the object itself or its descendent objects.
|
||||
For example, GObject class is declared in `gobject.h` in GLib source files.
|
||||
|
||||
1 typedef struct _GObjectClass GObjectClass;
|
||||
2 typedef struct _GObjectClass GInitiallyUnownedClass;
|
||||
3
|
||||
4 struct _GObjectClass {
|
||||
5 GTypeClass g_type_class;
|
||||
6 /*< private >*/
|
||||
7 GSList *construct_properties;
|
||||
8 /*< public >*/
|
||||
9 /* seldom overidden */
|
||||
10 GObject* (*constructor) (GType type,
|
||||
11 guint n_construct_properties,
|
||||
12 GObjectConstructParam *construct_properties);
|
||||
13 /* overridable methods */
|
||||
14 void (*set_property) (GObject *object,
|
||||
15 guint property_id,
|
||||
16 const GValue *value,
|
||||
17 GParamSpec *pspec);
|
||||
18 void (*get_property) (GObject *object,
|
||||
19 guint property_id,
|
||||
20 GValue *value,
|
||||
21 GParamSpec *pspec);
|
||||
22 void (*dispose) (GObject *object);
|
||||
23 void (*finalize) (GObject *object);
|
||||
24 /* seldom overidden */
|
||||
25 void (*dispatch_properties_changed) (GObject *object,
|
||||
26 guint n_pspecs,
|
||||
27 GParamSpec **pspecs);
|
||||
28 /* signals */
|
||||
29 void (*notify) (GObject *object,
|
||||
30 GParamSpec *pspec);
|
||||
31
|
||||
32 /* called when done constructing */
|
||||
33 void (*constructed) (GObject *object);
|
||||
34 /*< private >*/
|
||||
35 gsize flags;
|
||||
36 /* padding */
|
||||
37 gpointer pdummy[6];
|
||||
38 };
|
||||
~~~C
|
||||
1 typedef struct _GObjectClass GObjectClass;
|
||||
2 typedef struct _GObjectClass GInitiallyUnownedClass;
|
||||
3
|
||||
4 struct _GObjectClass {
|
||||
5 GTypeClass g_type_class;
|
||||
6 /*< private >*/
|
||||
7 GSList *construct_properties;
|
||||
8 /*< public >*/
|
||||
9 /* seldom overidden */
|
||||
10 GObject* (*constructor) (GType type,
|
||||
11 guint n_construct_properties,
|
||||
12 GObjectConstructParam *construct_properties);
|
||||
13 /* overridable methods */
|
||||
14 void (*set_property) (GObject *object,
|
||||
15 guint property_id,
|
||||
16 const GValue *value,
|
||||
17 GParamSpec *pspec);
|
||||
18 void (*get_property) (GObject *object,
|
||||
19 guint property_id,
|
||||
20 GValue *value,
|
||||
21 GParamSpec *pspec);
|
||||
22 void (*dispose) (GObject *object);
|
||||
23 void (*finalize) (GObject *object);
|
||||
24 /* seldom overidden */
|
||||
25 void (*dispatch_properties_changed) (GObject *object,
|
||||
26 guint n_pspecs,
|
||||
27 GParamSpec **pspecs);
|
||||
28 /* signals */
|
||||
29 void (*notify) (GObject *object,
|
||||
30 GParamSpec *pspec);
|
||||
31
|
||||
32 /* called when done constructing */
|
||||
33 void (*constructed) (GObject *object);
|
||||
34 /*< private >*/
|
||||
35 gsize flags;
|
||||
36 /* padding */
|
||||
37 gpointer pdummy[6];
|
||||
38 };
|
||||
~~~
|
||||
|
||||
I'd like to explain some of the members.
|
||||
There's a pointer to the function `dispose` in line 22.
|
||||
|
@ -218,114 +224,116 @@ Let's look at all the classes from GObject, which is the top level object, to Tf
|
|||
|
||||
The following is extracts from the source files (not exactly the same).
|
||||
|
||||
1 struct _GtkWidgetClass {
|
||||
2 GInitiallyUnownedClass parent_class;
|
||||
3 /*< public >*/
|
||||
4 guint activate_signal;
|
||||
5 /* basics */
|
||||
6 void (* show) (GtkWidget *widget);
|
||||
7 void (* hide) (GtkWidget *widget);
|
||||
8 void (* map) (GtkWidget *widget);
|
||||
9 void (* unmap) (GtkWidget *widget);
|
||||
10 void (* realize) (GtkWidget *widget);
|
||||
11 void (* unrealize) (GtkWidget *widget);
|
||||
12 void (* root) (GtkWidget *widget);
|
||||
13 void (* unroot) (GtkWidget *widget);
|
||||
14 void (* size_allocate) (GtkWidget *widget,
|
||||
15 int width,
|
||||
16 int height,
|
||||
17 int baseline);
|
||||
18 void (* state_flags_changed) (GtkWidget *widget,
|
||||
19 GtkStateFlags previous_state_flags);
|
||||
20 void (* direction_changed) (GtkWidget *widget,
|
||||
21 GtkTextDirection previous_direction);
|
||||
22 void (* grab_notify) (GtkWidget *widget,
|
||||
23 gboolean was_grabbed);
|
||||
24 /* size requests */
|
||||
25 GtkSizeRequestMode (* get_request_mode) (GtkWidget *widget);
|
||||
26 void (* measure) (GtkWidget *widget,
|
||||
27 GtkOrientation orientation,
|
||||
28 int for_size,
|
||||
29 int *minimum,
|
||||
30 int *natural,
|
||||
31 int *minimum_baseline,
|
||||
32 int *natural_baseline);
|
||||
33 /* Mnemonics */
|
||||
34 gboolean (* mnemonic_activate) (GtkWidget *widget,
|
||||
35 gboolean group_cycling);
|
||||
36 /* explicit focus */
|
||||
37 gboolean (* grab_focus) (GtkWidget *widget);
|
||||
38 gboolean (* focus) (GtkWidget *widget,
|
||||
39 GtkDirectionType direction);
|
||||
40 void (* set_focus_child) (GtkWidget *widget,
|
||||
41 GtkWidget *child);
|
||||
42 /* keyboard navigation */
|
||||
43 void (* move_focus) (GtkWidget *widget,
|
||||
44 GtkDirectionType direction);
|
||||
45 gboolean (* keynav_failed) (GtkWidget *widget,
|
||||
46 GtkDirectionType direction);
|
||||
47 /* accessibility support
|
||||
48 */
|
||||
49 AtkObject * (* get_accessible) (GtkWidget *widget);
|
||||
50 gboolean (* query_tooltip) (GtkWidget *widget,
|
||||
51 gint x,
|
||||
52 gint y,
|
||||
53 gboolean keyboard_tooltip,
|
||||
54 GtkTooltip *tooltip);
|
||||
55 void (* compute_expand) (GtkWidget *widget,
|
||||
56 gboolean *hexpand_p,
|
||||
57 gboolean *vexpand_p);
|
||||
58 void (* css_changed) (GtkWidget *widget,
|
||||
59 GtkCssStyleChange *change);
|
||||
60 void (* system_setting_changed) (GtkWidget *widget,
|
||||
61 GtkSystemSetting settings);
|
||||
62 void (* snapshot) (GtkWidget *widget,
|
||||
63 GtkSnapshot *snapshot);
|
||||
64 gboolean (* contains) (GtkWidget *widget,
|
||||
65 gdouble x,
|
||||
66 gdouble y);
|
||||
67 /*< private >*/
|
||||
68 GtkWidgetClassPrivate *priv;
|
||||
69 gpointer padding[8];
|
||||
70 };
|
||||
71
|
||||
72 struct _GtkTextViewClass {
|
||||
73 GtkWidgetClass parent_class;
|
||||
74 /*< public >*/
|
||||
75 void (* move_cursor) (GtkTextView *text_view,
|
||||
76 GtkMovementStep step,
|
||||
77 gint count,
|
||||
78 gboolean extend_selection);
|
||||
79 void (* set_anchor) (GtkTextView *text_view);
|
||||
80 void (* insert_at_cursor) (GtkTextView *text_view,
|
||||
81 const gchar *str);
|
||||
82 void (* delete_from_cursor) (GtkTextView *text_view,
|
||||
83 GtkDeleteType type,
|
||||
84 gint count);
|
||||
85 void (* backspace) (GtkTextView *text_view);
|
||||
86 void (* cut_clipboard) (GtkTextView *text_view);
|
||||
87 void (* copy_clipboard) (GtkTextView *text_view);
|
||||
88 void (* paste_clipboard) (GtkTextView *text_view);
|
||||
89 void (* toggle_overwrite) (GtkTextView *text_view);
|
||||
90 GtkTextBuffer * (* create_buffer) (GtkTextView *text_view);
|
||||
91 void (* snapshot_layer) (GtkTextView *text_view,
|
||||
92 GtkTextViewLayer layer,
|
||||
93 GtkSnapshot *snapshot);
|
||||
94 gboolean (* extend_selection) (GtkTextView *text_view,
|
||||
95 GtkTextExtendSelection granularity,
|
||||
96 const GtkTextIter *location,
|
||||
97 GtkTextIter *start,
|
||||
98 GtkTextIter *end);
|
||||
99 void (* insert_emoji) (GtkTextView *text_view);
|
||||
100 /*< private >*/
|
||||
101 gpointer padding[8];
|
||||
102 };
|
||||
103
|
||||
104 /* The following definition is generated by the macro G_DECLARE_FINAL_TYPE
|
||||
105 typedef struct {
|
||||
106 GtkTextView parent_class;
|
||||
107 } TfeTextViewClass;
|
||||
108
|
||||
~~~C
|
||||
1 struct _GtkWidgetClass {
|
||||
2 GInitiallyUnownedClass parent_class;
|
||||
3 /*< public >*/
|
||||
4 guint activate_signal;
|
||||
5 /* basics */
|
||||
6 void (* show) (GtkWidget *widget);
|
||||
7 void (* hide) (GtkWidget *widget);
|
||||
8 void (* map) (GtkWidget *widget);
|
||||
9 void (* unmap) (GtkWidget *widget);
|
||||
10 void (* realize) (GtkWidget *widget);
|
||||
11 void (* unrealize) (GtkWidget *widget);
|
||||
12 void (* root) (GtkWidget *widget);
|
||||
13 void (* unroot) (GtkWidget *widget);
|
||||
14 void (* size_allocate) (GtkWidget *widget,
|
||||
15 int width,
|
||||
16 int height,
|
||||
17 int baseline);
|
||||
18 void (* state_flags_changed) (GtkWidget *widget,
|
||||
19 GtkStateFlags previous_state_flags);
|
||||
20 void (* direction_changed) (GtkWidget *widget,
|
||||
21 GtkTextDirection previous_direction);
|
||||
22 void (* grab_notify) (GtkWidget *widget,
|
||||
23 gboolean was_grabbed);
|
||||
24 /* size requests */
|
||||
25 GtkSizeRequestMode (* get_request_mode) (GtkWidget *widget);
|
||||
26 void (* measure) (GtkWidget *widget,
|
||||
27 GtkOrientation orientation,
|
||||
28 int for_size,
|
||||
29 int *minimum,
|
||||
30 int *natural,
|
||||
31 int *minimum_baseline,
|
||||
32 int *natural_baseline);
|
||||
33 /* Mnemonics */
|
||||
34 gboolean (* mnemonic_activate) (GtkWidget *widget,
|
||||
35 gboolean group_cycling);
|
||||
36 /* explicit focus */
|
||||
37 gboolean (* grab_focus) (GtkWidget *widget);
|
||||
38 gboolean (* focus) (GtkWidget *widget,
|
||||
39 GtkDirectionType direction);
|
||||
40 void (* set_focus_child) (GtkWidget *widget,
|
||||
41 GtkWidget *child);
|
||||
42 /* keyboard navigation */
|
||||
43 void (* move_focus) (GtkWidget *widget,
|
||||
44 GtkDirectionType direction);
|
||||
45 gboolean (* keynav_failed) (GtkWidget *widget,
|
||||
46 GtkDirectionType direction);
|
||||
47 /* accessibility support
|
||||
48 */
|
||||
49 AtkObject * (* get_accessible) (GtkWidget *widget);
|
||||
50 gboolean (* query_tooltip) (GtkWidget *widget,
|
||||
51 gint x,
|
||||
52 gint y,
|
||||
53 gboolean keyboard_tooltip,
|
||||
54 GtkTooltip *tooltip);
|
||||
55 void (* compute_expand) (GtkWidget *widget,
|
||||
56 gboolean *hexpand_p,
|
||||
57 gboolean *vexpand_p);
|
||||
58 void (* css_changed) (GtkWidget *widget,
|
||||
59 GtkCssStyleChange *change);
|
||||
60 void (* system_setting_changed) (GtkWidget *widget,
|
||||
61 GtkSystemSetting settings);
|
||||
62 void (* snapshot) (GtkWidget *widget,
|
||||
63 GtkSnapshot *snapshot);
|
||||
64 gboolean (* contains) (GtkWidget *widget,
|
||||
65 gdouble x,
|
||||
66 gdouble y);
|
||||
67 /*< private >*/
|
||||
68 GtkWidgetClassPrivate *priv;
|
||||
69 gpointer padding[8];
|
||||
70 };
|
||||
71
|
||||
72 struct _GtkTextViewClass {
|
||||
73 GtkWidgetClass parent_class;
|
||||
74 /*< public >*/
|
||||
75 void (* move_cursor) (GtkTextView *text_view,
|
||||
76 GtkMovementStep step,
|
||||
77 gint count,
|
||||
78 gboolean extend_selection);
|
||||
79 void (* set_anchor) (GtkTextView *text_view);
|
||||
80 void (* insert_at_cursor) (GtkTextView *text_view,
|
||||
81 const gchar *str);
|
||||
82 void (* delete_from_cursor) (GtkTextView *text_view,
|
||||
83 GtkDeleteType type,
|
||||
84 gint count);
|
||||
85 void (* backspace) (GtkTextView *text_view);
|
||||
86 void (* cut_clipboard) (GtkTextView *text_view);
|
||||
87 void (* copy_clipboard) (GtkTextView *text_view);
|
||||
88 void (* paste_clipboard) (GtkTextView *text_view);
|
||||
89 void (* toggle_overwrite) (GtkTextView *text_view);
|
||||
90 GtkTextBuffer * (* create_buffer) (GtkTextView *text_view);
|
||||
91 void (* snapshot_layer) (GtkTextView *text_view,
|
||||
92 GtkTextViewLayer layer,
|
||||
93 GtkSnapshot *snapshot);
|
||||
94 gboolean (* extend_selection) (GtkTextView *text_view,
|
||||
95 GtkTextExtendSelection granularity,
|
||||
96 const GtkTextIter *location,
|
||||
97 GtkTextIter *start,
|
||||
98 GtkTextIter *end);
|
||||
99 void (* insert_emoji) (GtkTextView *text_view);
|
||||
100 /*< private >*/
|
||||
101 gpointer padding[8];
|
||||
102 };
|
||||
103
|
||||
104 /* The following definition is generated by the macro G_DECLARE_FINAL_TYPE
|
||||
105 typedef struct {
|
||||
106 GtkTextView parent_class;
|
||||
107 } TfeTextViewClass;
|
||||
108
|
||||
~~~
|
||||
|
||||
- 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`.
|
||||
|
@ -370,15 +378,17 @@ In the destruction process of TfeTextView, the reference count of widgets relate
|
|||
But GFile pointed by `tv->file` needs to decrease its reference count by one.
|
||||
You must write the code in the dispose handler `tfe_text_view_dispose`.
|
||||
|
||||
1 static void
|
||||
2 tfe_text_view_dispose (GObject *gobject) {
|
||||
3 TfeTextView *tv = TFE_TEXT_VIEW (gobject);
|
||||
4
|
||||
5 if (G_IS_FILE (tv->file))
|
||||
6 g_clear_object (&tv->file);
|
||||
7
|
||||
8 G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
|
||||
9 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 tfe_text_view_dispose (GObject *gobject) {
|
||||
3 TfeTextView *tv = TFE_TEXT_VIEW (gobject);
|
||||
4
|
||||
5 if (G_IS_FILE (tv->file))
|
||||
6 g_clear_object (&tv->file);
|
||||
7
|
||||
8 G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
|
||||
9 }
|
||||
~~~
|
||||
|
||||
- 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`.
|
||||
|
|
56
gfm/sec11.md
56
gfm/sec11.md
|
@ -55,33 +55,35 @@ If you need to register two or more signals, static array is usually used.
|
|||
|
||||
Signal registration codes are written in the class initialization function.
|
||||
|
||||
1 static void
|
||||
2 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
3 GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
4
|
||||
5 object_class->dispose = tfe_text_view_dispose;
|
||||
6 tfe_text_view_signals[CHANGE_FILE] = g_signal_newv ("change-file",
|
||||
7 G_TYPE_FROM_CLASS (class),
|
||||
8 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
||||
9 NULL /* closure */,
|
||||
10 NULL /* accumulator */,
|
||||
11 NULL /* accumulator data */,
|
||||
12 NULL /* C marshaller */,
|
||||
13 G_TYPE_NONE /* return_type */,
|
||||
14 0 /* n_params */,
|
||||
15 NULL /* param_types */);
|
||||
16 GType param_types[] = {G_TYPE_INT};
|
||||
17 tfe_text_view_signals[OPEN_RESPONSE] = g_signal_newv ("open-response",
|
||||
18 G_TYPE_FROM_CLASS (class),
|
||||
19 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
||||
20 NULL /* closure */,
|
||||
21 NULL /* accumulator */,
|
||||
22 NULL /* accumulator data */,
|
||||
23 NULL /* C marshaller */,
|
||||
24 G_TYPE_NONE /* return_type */,
|
||||
25 1 /* n_params */,
|
||||
26 param_types);
|
||||
27 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
3 GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
4
|
||||
5 object_class->dispose = tfe_text_view_dispose;
|
||||
6 tfe_text_view_signals[CHANGE_FILE] = g_signal_newv ("change-file",
|
||||
7 G_TYPE_FROM_CLASS (class),
|
||||
8 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
||||
9 NULL /* closure */,
|
||||
10 NULL /* accumulator */,
|
||||
11 NULL /* accumulator data */,
|
||||
12 NULL /* C marshaller */,
|
||||
13 G_TYPE_NONE /* return_type */,
|
||||
14 0 /* n_params */,
|
||||
15 NULL /* param_types */);
|
||||
16 GType param_types[] = {G_TYPE_INT};
|
||||
17 tfe_text_view_signals[OPEN_RESPONSE] = g_signal_newv ("open-response",
|
||||
18 G_TYPE_FROM_CLASS (class),
|
||||
19 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
||||
20 NULL /* closure */,
|
||||
21 NULL /* accumulator */,
|
||||
22 NULL /* accumulator data */,
|
||||
23 NULL /* C marshaller */,
|
||||
24 G_TYPE_NONE /* return_type */,
|
||||
25 1 /* n_params */,
|
||||
26 param_types);
|
||||
27 }
|
||||
~~~
|
||||
|
||||
- 6-15: Register "change-file"signal.
|
||||
`g_signal_newv` function is used.
|
||||
|
|
376
gfm/sec12.md
376
gfm/sec12.md
|
@ -9,42 +9,46 @@ In this section I will explain each function in TfeTextView object.
|
|||
`tfe.h` is a top header file and it includes `gtk.h` and all the header files.
|
||||
Every C source files, which are `tfeapplication.c`, `tfenotebook.c` and `tfetextview.c`, include `tfe.h` at the beginning of each file.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #include "tfetextview.h"
|
||||
4 #include "tfenotebook.h"
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #include "tfetextview.h"
|
||||
4 #include "tfenotebook.h"
|
||||
~~~
|
||||
|
||||
`tfetextview.h` is a header file which describes the public functions in `tfetextview.c`.
|
||||
|
||||
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
3
|
||||
4 /* "open-response" signal response */
|
||||
5 enum
|
||||
6 {
|
||||
7 TFE_OPEN_RESPONSE_SUCCESS,
|
||||
8 TFE_OPEN_RESPONSE_CANCEL,
|
||||
9 TFE_OPEN_RESPONSE_ERROR
|
||||
10 };
|
||||
11
|
||||
12 GFile *
|
||||
13 tfe_text_view_get_file (TfeTextView *tv);
|
||||
14
|
||||
15 void
|
||||
16 tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
||||
17
|
||||
18 void
|
||||
19 tfe_text_view_save (TfeTextView *tv);
|
||||
20
|
||||
21 void
|
||||
22 tfe_text_view_saveas (TfeTextView *tv);
|
||||
23
|
||||
24 GtkWidget *
|
||||
25 tfe_text_view_new_with_file (GFile *file);
|
||||
26
|
||||
27 GtkWidget *
|
||||
28 tfe_text_view_new (void);
|
||||
29
|
||||
~~~C
|
||||
1 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
2 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
3
|
||||
4 /* "open-response" signal response */
|
||||
5 enum
|
||||
6 {
|
||||
7 TFE_OPEN_RESPONSE_SUCCESS,
|
||||
8 TFE_OPEN_RESPONSE_CANCEL,
|
||||
9 TFE_OPEN_RESPONSE_ERROR
|
||||
10 };
|
||||
11
|
||||
12 GFile *
|
||||
13 tfe_text_view_get_file (TfeTextView *tv);
|
||||
14
|
||||
15 void
|
||||
16 tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
||||
17
|
||||
18 void
|
||||
19 tfe_text_view_save (TfeTextView *tv);
|
||||
20
|
||||
21 void
|
||||
22 tfe_text_view_saveas (TfeTextView *tv);
|
||||
23
|
||||
24 GtkWidget *
|
||||
25 tfe_text_view_new_with_file (GFile *file);
|
||||
26
|
||||
27 GtkWidget *
|
||||
28 tfe_text_view_new (void);
|
||||
29
|
||||
~~~
|
||||
|
||||
- 1-2: These two lines are used to define TfeTextView.
|
||||
- 4-10: Definitions of parameter used in the handler of "open-response" signal.
|
||||
|
@ -75,30 +79,32 @@ If an error occures during the genration process, NULL is returned.
|
|||
|
||||
Each function is defined as follows.
|
||||
|
||||
1 GtkWidget *
|
||||
2 tfe_text_view_new_with_file (GFile *file) {
|
||||
3 g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
4
|
||||
5 GtkWidget *tv;
|
||||
6 GtkTextBuffer *tb;
|
||||
7 char *contents;
|
||||
8 gsize length;
|
||||
9
|
||||
10 if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
|
||||
11 return NULL;
|
||||
12
|
||||
13 tv = tfe_text_view_new();
|
||||
14 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
15 gtk_text_buffer_set_text (tb, contents, length);
|
||||
16 g_free (contents);
|
||||
17 TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
|
||||
18 return tv;
|
||||
19 }
|
||||
20
|
||||
21 GtkWidget *
|
||||
22 tfe_text_view_new (void) {
|
||||
23 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
24 }
|
||||
~~~C
|
||||
1 GtkWidget *
|
||||
2 tfe_text_view_new_with_file (GFile *file) {
|
||||
3 g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
4
|
||||
5 GtkWidget *tv;
|
||||
6 GtkTextBuffer *tb;
|
||||
7 char *contents;
|
||||
8 gsize length;
|
||||
9
|
||||
10 if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
|
||||
11 return NULL;
|
||||
12
|
||||
13 tv = tfe_text_view_new();
|
||||
14 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
15 gtk_text_buffer_set_text (tb, contents, length);
|
||||
16 g_free (contents);
|
||||
17 TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
|
||||
18 return tv;
|
||||
19 }
|
||||
20
|
||||
21 GtkWidget *
|
||||
22 tfe_text_view_new (void) {
|
||||
23 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
24 }
|
||||
~~~
|
||||
|
||||
- 21-24: `tfe_text_view_new`.
|
||||
Just returns the value from the function `g_object_new` but casted to the pointer to GtkWidget.
|
||||
|
@ -137,76 +143,78 @@ If `tv->file` is NULL, then it shows GtkFileChooserDialog and lets the user to g
|
|||
If an error occures, it is shown to the user through the message dialog.
|
||||
The error is managed only in the object and no information is notified to the caller.
|
||||
|
||||
1 static void
|
||||
2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4 GFile *file;
|
||||
5
|
||||
6 if (response == GTK_RESPONSE_ACCEPT) {
|
||||
7 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
8 if (G_IS_FILE(file)) {
|
||||
9 tv->file = file;
|
||||
10 gtk_text_buffer_set_modified (tb, TRUE);
|
||||
11 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||
12 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
13 }
|
||||
14 }
|
||||
15 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
16 }
|
||||
17
|
||||
18 void
|
||||
19 tfe_text_view_save (TfeTextView *tv) {
|
||||
20 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
21
|
||||
22 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
23 GtkTextIter start_iter;
|
||||
24 GtkTextIter end_iter;
|
||||
25 gchar *contents;
|
||||
26 GtkWidget *message_dialog;
|
||||
27 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||
28 GError *err = NULL;
|
||||
29
|
||||
30 if (! gtk_text_buffer_get_modified (tb))
|
||||
31 return; /* no necessary to save it */
|
||||
32 else if (tv->file == NULL)
|
||||
33 tfe_text_view_saveas (tv);
|
||||
34 else {
|
||||
35 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
36 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
37 if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err))
|
||||
38 gtk_text_buffer_set_modified (tb, FALSE);
|
||||
39 else {
|
||||
40 /* It is possible that tv->file is broken. */
|
||||
41 /* It is a good idea to set tv->file to NULL. */
|
||||
42 if (G_IS_FILE (tv->file))
|
||||
43 g_object_unref (tv->file);
|
||||
44 tv->file =NULL;
|
||||
45 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||
46 gtk_text_buffer_set_modified (tb, TRUE);
|
||||
47 message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
|
||||
48 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
49 "%s.\n", err->message);
|
||||
50 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
51 gtk_widget_show (message_dialog);
|
||||
52 g_error_free (err);
|
||||
53 }
|
||||
54 }
|
||||
55 }
|
||||
56
|
||||
57 void
|
||||
58 tfe_text_view_saveas (TfeTextView *tv) {
|
||||
59 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
60
|
||||
61 GtkWidget *dialog;
|
||||
62 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||
63
|
||||
64 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
65 "_Cancel", GTK_RESPONSE_CANCEL,
|
||||
66 "_Save", GTK_RESPONSE_ACCEPT,
|
||||
67 NULL);
|
||||
68 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
||||
69 gtk_widget_show (dialog);
|
||||
70 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4 GFile *file;
|
||||
5
|
||||
6 if (response == GTK_RESPONSE_ACCEPT) {
|
||||
7 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
8 if (G_IS_FILE(file)) {
|
||||
9 tv->file = file;
|
||||
10 gtk_text_buffer_set_modified (tb, TRUE);
|
||||
11 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||
12 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
13 }
|
||||
14 }
|
||||
15 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
16 }
|
||||
17
|
||||
18 void
|
||||
19 tfe_text_view_save (TfeTextView *tv) {
|
||||
20 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
21
|
||||
22 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
23 GtkTextIter start_iter;
|
||||
24 GtkTextIter end_iter;
|
||||
25 gchar *contents;
|
||||
26 GtkWidget *message_dialog;
|
||||
27 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||
28 GError *err = NULL;
|
||||
29
|
||||
30 if (! gtk_text_buffer_get_modified (tb))
|
||||
31 return; /* no necessary to save it */
|
||||
32 else if (tv->file == NULL)
|
||||
33 tfe_text_view_saveas (tv);
|
||||
34 else {
|
||||
35 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
36 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
37 if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err))
|
||||
38 gtk_text_buffer_set_modified (tb, FALSE);
|
||||
39 else {
|
||||
40 /* It is possible that tv->file is broken. */
|
||||
41 /* It is a good idea to set tv->file to NULL. */
|
||||
42 if (G_IS_FILE (tv->file))
|
||||
43 g_object_unref (tv->file);
|
||||
44 tv->file =NULL;
|
||||
45 g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||
46 gtk_text_buffer_set_modified (tb, TRUE);
|
||||
47 message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
|
||||
48 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
49 "%s.\n", err->message);
|
||||
50 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
51 gtk_widget_show (message_dialog);
|
||||
52 g_error_free (err);
|
||||
53 }
|
||||
54 }
|
||||
55 }
|
||||
56
|
||||
57 void
|
||||
58 tfe_text_view_saveas (TfeTextView *tv) {
|
||||
59 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
60
|
||||
61 GtkWidget *dialog;
|
||||
62 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||
63
|
||||
64 dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
65 "_Cancel", GTK_RESPONSE_CANCEL,
|
||||
66 "_Save", GTK_RESPONSE_ACCEPT,
|
||||
67 NULL);
|
||||
68 g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
|
||||
69 gtk_widget_show (dialog);
|
||||
70 }
|
||||
~~~
|
||||
|
||||
- 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.
|
||||
|
@ -258,55 +266,57 @@ Otherwise probably bad things will happen.
|
|||
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`.
|
||||
|
||||
1 static void
|
||||
2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4 GFile *file;
|
||||
5 char *contents;
|
||||
6 gsize length;
|
||||
7 GtkWidget *message_dialog;
|
||||
8 GError *err = NULL;
|
||||
9
|
||||
10 if (response != GTK_RESPONSE_ACCEPT)
|
||||
11 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
|
||||
12 else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog))))
|
||||
13 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||
14 else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
|
||||
15 if (G_IS_FILE (file))
|
||||
16 g_object_unref (file);
|
||||
17 message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
|
||||
18 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
19 "%s.\n", err->message);
|
||||
20 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
21 gtk_widget_show (message_dialog);
|
||||
22 g_error_free (err);
|
||||
23 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||
24 } else {
|
||||
25 gtk_text_buffer_set_text (tb, contents, length);
|
||||
26 g_free (contents);
|
||||
27 if (G_IS_FILE (tv->file))
|
||||
28 g_object_unref (tv->file);
|
||||
29 tv->file = file;
|
||||
30 gtk_text_buffer_set_modified (tb, FALSE);
|
||||
31 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
|
||||
32 }
|
||||
33 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
34 }
|
||||
35
|
||||
36 void
|
||||
37 tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
|
||||
38 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
39 g_return_if_fail (GTK_IS_WINDOW (win));
|
||||
40
|
||||
41 GtkWidget *dialog;
|
||||
42
|
||||
43 dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
44 "Cancel", GTK_RESPONSE_CANCEL,
|
||||
45 "Open", GTK_RESPONSE_ACCEPT,
|
||||
46 NULL);
|
||||
47 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
|
||||
48 gtk_widget_show (dialog);
|
||||
49 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4 GFile *file;
|
||||
5 char *contents;
|
||||
6 gsize length;
|
||||
7 GtkWidget *message_dialog;
|
||||
8 GError *err = NULL;
|
||||
9
|
||||
10 if (response != GTK_RESPONSE_ACCEPT)
|
||||
11 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
|
||||
12 else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog))))
|
||||
13 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||
14 else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
|
||||
15 if (G_IS_FILE (file))
|
||||
16 g_object_unref (file);
|
||||
17 message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
|
||||
18 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
19 "%s.\n", err->message);
|
||||
20 g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
21 gtk_widget_show (message_dialog);
|
||||
22 g_error_free (err);
|
||||
23 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||
24 } else {
|
||||
25 gtk_text_buffer_set_text (tb, contents, length);
|
||||
26 g_free (contents);
|
||||
27 if (G_IS_FILE (tv->file))
|
||||
28 g_object_unref (tv->file);
|
||||
29 tv->file = file;
|
||||
30 gtk_text_buffer_set_modified (tb, FALSE);
|
||||
31 g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
|
||||
32 }
|
||||
33 gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
34 }
|
||||
35
|
||||
36 void
|
||||
37 tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
|
||||
38 g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
39 g_return_if_fail (GTK_IS_WINDOW (win));
|
||||
40
|
||||
41 GtkWidget *dialog;
|
||||
42
|
||||
43 dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
44 "Cancel", GTK_RESPONSE_CANCEL,
|
||||
45 "Open", GTK_RESPONSE_ACCEPT,
|
||||
46 NULL);
|
||||
47 g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
|
||||
48 gtk_widget_show (dialog);
|
||||
49 }
|
||||
~~~
|
||||
|
||||
- 36-49: `tfe_text_view_open` function.
|
||||
- 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.
|
||||
|
||||
1 GFile *
|
||||
2 tfe_text_view_get_file (TfeTextView *tv) {
|
||||
3 g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
|
||||
4
|
||||
5 return g_file_dup (tv->file);
|
||||
6 }
|
||||
~~~C
|
||||
1 GFile *
|
||||
2 tfe_text_view_get_file (TfeTextView *tv) {
|
||||
3 g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
|
||||
4
|
||||
5 return g_file_dup (tv->file);
|
||||
6 }
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
|
250
gfm/sec13.md
250
gfm/sec13.md
|
@ -6,18 +6,20 @@ GtkNotebook is a very important object in the text file editor `tfe`.
|
|||
It connects the application and TfeTextView objects.
|
||||
`tfenotebook.h` and `tfenotebook.c` have a set of functions related to GtkTextbook.
|
||||
|
||||
1 void
|
||||
2 notebook_page_save(GtkNotebook *nb);
|
||||
3
|
||||
4 void
|
||||
5 notebook_page_open (GtkNotebook *nb);
|
||||
6
|
||||
7 void
|
||||
8 notebook_page_new_with_file (GtkNotebook *nb, GFile *file);
|
||||
9
|
||||
10 void
|
||||
11 notebook_page_new (GtkNotebook *nb);
|
||||
12
|
||||
~~~C
|
||||
1 void
|
||||
2 notebook_page_save(GtkNotebook *nb);
|
||||
3
|
||||
4 void
|
||||
5 notebook_page_open (GtkNotebook *nb);
|
||||
6
|
||||
7 void
|
||||
8 notebook_page_new_with_file (GtkNotebook *nb, GFile *file);
|
||||
9
|
||||
10 void
|
||||
11 notebook_page_new (GtkNotebook *nb);
|
||||
12
|
||||
~~~
|
||||
|
||||
This header file shows the public functions in `tfenotebook.c`.
|
||||
|
||||
|
@ -44,43 +46,45 @@ Now let's look at each program of the functions.
|
|||
|
||||
## notebook\_page\_new
|
||||
|
||||
1 static gchar*
|
||||
2 get_untitled () {
|
||||
3 static int c = -1;
|
||||
4 if (++c == 0)
|
||||
5 return g_strdup_printf("Untitled");
|
||||
6 else
|
||||
7 return g_strdup_printf ("Untitled%u", c);
|
||||
8 }
|
||||
9
|
||||
10 static void
|
||||
11 notebook_page_build (GtkNotebook *nb, GtkWidget *tv, char *filename) {
|
||||
12 GtkWidget *scr;
|
||||
13 GtkNotebookPage *nbp;
|
||||
14 GtkWidget *lab;
|
||||
15 gint i;
|
||||
16 scr = gtk_scrolled_window_new ();
|
||||
17
|
||||
18 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
19 lab = gtk_label_new (filename);
|
||||
20 i = gtk_notebook_append_page (nb, scr, lab);
|
||||
21 nbp = gtk_notebook_get_page (nb, scr);
|
||||
22 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
23 gtk_notebook_set_current_page (nb, i);
|
||||
24 g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed), nb);
|
||||
25 }
|
||||
26
|
||||
27 void
|
||||
28 notebook_page_new (GtkNotebook *nb) {
|
||||
29 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||
30
|
||||
31 GtkWidget *tv;
|
||||
32 char *filename;
|
||||
33
|
||||
34 tv = tfe_text_view_new ();
|
||||
35 filename = get_untitled ();
|
||||
36 notebook_page_build (nb, tv, filename);
|
||||
37 }
|
||||
~~~C
|
||||
1 static gchar*
|
||||
2 get_untitled () {
|
||||
3 static int c = -1;
|
||||
4 if (++c == 0)
|
||||
5 return g_strdup_printf("Untitled");
|
||||
6 else
|
||||
7 return g_strdup_printf ("Untitled%u", c);
|
||||
8 }
|
||||
9
|
||||
10 static void
|
||||
11 notebook_page_build (GtkNotebook *nb, GtkWidget *tv, char *filename) {
|
||||
12 GtkWidget *scr;
|
||||
13 GtkNotebookPage *nbp;
|
||||
14 GtkWidget *lab;
|
||||
15 gint i;
|
||||
16 scr = gtk_scrolled_window_new ();
|
||||
17
|
||||
18 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
19 lab = gtk_label_new (filename);
|
||||
20 i = gtk_notebook_append_page (nb, scr, lab);
|
||||
21 nbp = gtk_notebook_get_page (nb, scr);
|
||||
22 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
23 gtk_notebook_set_current_page (nb, i);
|
||||
24 g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed), nb);
|
||||
25 }
|
||||
26
|
||||
27 void
|
||||
28 notebook_page_new (GtkNotebook *nb) {
|
||||
29 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||
30
|
||||
31 GtkWidget *tv;
|
||||
32 char *filename;
|
||||
33
|
||||
34 tv = tfe_text_view_new ();
|
||||
35 filename = get_untitled ();
|
||||
36 notebook_page_build (nb, tv, filename);
|
||||
37 }
|
||||
~~~
|
||||
|
||||
- 27-37: `notebook_page_new` function.
|
||||
- 29: `g_return_if_fail` is used to check the argument.
|
||||
|
@ -102,19 +106,21 @@ The caller of `get_untitled` is in charge of freeing the memories of the string.
|
|||
|
||||
## notebook\_page\_new\_with\_file
|
||||
|
||||
1 void
|
||||
2 notebook_page_new_with_file (GtkNotebook *nb, GFile *file) {
|
||||
3 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||
4 g_return_if_fail(G_IS_FILE (file));
|
||||
5
|
||||
6 GtkWidget *tv;
|
||||
7 char *filename;
|
||||
8
|
||||
9 if ((tv = tfe_text_view_new_with_file (file)) == NULL)
|
||||
10 return; /* read error */
|
||||
11 filename = g_file_get_basename (file);
|
||||
12 notebook_page_build (nb, tv, filename);
|
||||
13 }
|
||||
~~~C
|
||||
1 void
|
||||
2 notebook_page_new_with_file (GtkNotebook *nb, GFile *file) {
|
||||
3 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||
4 g_return_if_fail(G_IS_FILE (file));
|
||||
5
|
||||
6 GtkWidget *tv;
|
||||
7 char *filename;
|
||||
8
|
||||
9 if ((tv = tfe_text_view_new_with_file (file)) == NULL)
|
||||
10 return; /* read error */
|
||||
11 filename = g_file_get_basename (file);
|
||||
12 notebook_page_build (nb, tv, filename);
|
||||
13 }
|
||||
~~~
|
||||
|
||||
- 9-10: Call `tfe_text_view_new_with_file`.
|
||||
If it returns NULL, then do nothing and return because of an error.
|
||||
|
@ -122,34 +128,36 @@ If it returns NULL, then do nothing and return because of an error.
|
|||
|
||||
## notebook\_page\_open
|
||||
|
||||
1 static void
|
||||
2 open_response (TfeTextView *tv, gint response, GtkNotebook *nb) {
|
||||
3 GFile *file;
|
||||
4 char *filename;
|
||||
5
|
||||
6 if (response != TFE_OPEN_RESPONSE_SUCCESS) {
|
||||
7 g_object_ref_sink (tv);
|
||||
8 g_object_unref (tv);
|
||||
9 }else if (! G_IS_FILE (file = tfe_text_view_get_file (tv))) {
|
||||
10 g_object_ref_sink (tv);
|
||||
11 g_object_unref (tv);
|
||||
12 }else {
|
||||
13 filename = g_file_get_basename (file);
|
||||
14 g_object_unref (file);
|
||||
15 notebook_page_build (nb, GTK_WIDGET (tv), filename);
|
||||
16 }
|
||||
17 }
|
||||
18
|
||||
19 void
|
||||
20 notebook_page_open (GtkNotebook *nb) {
|
||||
21 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||
22
|
||||
23 GtkWidget *tv;
|
||||
24
|
||||
25 tv = tfe_text_view_new ();
|
||||
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));
|
||||
28 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 open_response (TfeTextView *tv, gint response, GtkNotebook *nb) {
|
||||
3 GFile *file;
|
||||
4 char *filename;
|
||||
5
|
||||
6 if (response != TFE_OPEN_RESPONSE_SUCCESS) {
|
||||
7 g_object_ref_sink (tv);
|
||||
8 g_object_unref (tv);
|
||||
9 }else if (! G_IS_FILE (file = tfe_text_view_get_file (tv))) {
|
||||
10 g_object_ref_sink (tv);
|
||||
11 g_object_unref (tv);
|
||||
12 }else {
|
||||
13 filename = g_file_get_basename (file);
|
||||
14 g_object_unref (file);
|
||||
15 notebook_page_build (nb, GTK_WIDGET (tv), filename);
|
||||
16 }
|
||||
17 }
|
||||
18
|
||||
19 void
|
||||
20 notebook_page_open (GtkNotebook *nb) {
|
||||
21 g_return_if_fail(GTK_IS_NOTEBOOK (nb));
|
||||
22
|
||||
23 GtkWidget *tv;
|
||||
24
|
||||
25 tv = tfe_text_view_new ();
|
||||
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));
|
||||
28 }
|
||||
~~~
|
||||
|
||||
- 19-28: `notebook_page_open` function.
|
||||
- 25: Generate TfeTextView object.
|
||||
|
@ -169,17 +177,19 @@ Get the filename, build the contents of the page.
|
|||
|
||||
## notebook\_page\_save
|
||||
|
||||
1 void
|
||||
2 notebook_page_save(GtkNotebook *nb) {
|
||||
3 gint i;
|
||||
4 GtkWidget *scr;
|
||||
5 GtkWidget *tv;
|
||||
6
|
||||
7 i = gtk_notebook_get_current_page (nb);
|
||||
8 scr = gtk_notebook_get_nth_page (nb, i);
|
||||
9 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||
10 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
11 }
|
||||
~~~C
|
||||
1 void
|
||||
2 notebook_page_save(GtkNotebook *nb) {
|
||||
3 gint i;
|
||||
4 GtkWidget *scr;
|
||||
5 GtkWidget *tv;
|
||||
6
|
||||
7 i = gtk_notebook_get_current_page (nb);
|
||||
8 scr = gtk_notebook_get_nth_page (nb, i);
|
||||
9 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||
10 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
11 }
|
||||
~~~
|
||||
|
||||
- 7-9: Get TfeTextView belongs to the current notebook page.
|
||||
- 10: Call `tfe_text_view_save`.
|
||||
|
@ -190,24 +200,26 @@ The function `file_changed` is a handler connected to "change-file" signal.
|
|||
If `tv->file` is changed, TfeTextView emits this signal.
|
||||
This handler changes the label of GtkNotebookPage.
|
||||
|
||||
1 static void
|
||||
2 file_changed (TfeTextView *tv, GtkNotebook *nb) {
|
||||
3 GFile *file;
|
||||
4 char *filename;
|
||||
5 GtkWidget *scr;
|
||||
6 GtkWidget *label;
|
||||
7
|
||||
8 file = tfe_text_view_get_file (tv);
|
||||
9 scr = gtk_widget_get_parent (GTK_WIDGET (tv));
|
||||
10 if (G_IS_FILE (file))
|
||||
11 filename = g_file_get_basename (file);
|
||||
12 else
|
||||
13 filename = get_untitled ();
|
||||
14 label = gtk_label_new (filename);
|
||||
15 gtk_notebook_set_tab_label (nb, scr, label);
|
||||
16 g_object_unref (file);
|
||||
17 g_free (filename);
|
||||
18 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 file_changed (TfeTextView *tv, GtkNotebook *nb) {
|
||||
3 GFile *file;
|
||||
4 char *filename;
|
||||
5 GtkWidget *scr;
|
||||
6 GtkWidget *label;
|
||||
7
|
||||
8 file = tfe_text_view_get_file (tv);
|
||||
9 scr = gtk_widget_get_parent (GTK_WIDGET (tv));
|
||||
10 if (G_IS_FILE (file))
|
||||
11 filename = g_file_get_basename (file);
|
||||
12 else
|
||||
13 filename = get_untitled ();
|
||||
14 label = gtk_label_new (filename);
|
||||
15 gtk_notebook_set_tab_label (nb, scr, label);
|
||||
16 g_object_unref (file);
|
||||
17 g_free (filename);
|
||||
18 }
|
||||
~~~
|
||||
|
||||
- 8: Get GFile from TfeTextView.
|
||||
- 9: Get GkScrolledWindow which is the parent widget of `tv`.
|
||||
|
|
250
gfm/sec14.md
250
gfm/sec14.md
|
@ -15,21 +15,23 @@ It does following things.
|
|||
Th function `main` is the first invoked function in C language.
|
||||
It connects the command line given by the user and GTK application.
|
||||
|
||||
1 int
|
||||
2 main (int argc, char **argv) {
|
||||
3 GtkApplication *app;
|
||||
4 int stat;
|
||||
5
|
||||
6 app = gtk_application_new ("com.github.ToshioCP.tfe", G_APPLICATION_HANDLES_OPEN);
|
||||
7
|
||||
8 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
||||
9 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
||||
10 g_signal_connect (app, "open", G_CALLBACK (tfe_open), NULL);
|
||||
11
|
||||
12 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
13 g_object_unref (app);
|
||||
14 return stat;
|
||||
15 }
|
||||
~~~C
|
||||
1 int
|
||||
2 main (int argc, char **argv) {
|
||||
3 GtkApplication *app;
|
||||
4 int stat;
|
||||
5
|
||||
6 app = gtk_application_new ("com.github.ToshioCP.tfe", G_APPLICATION_HANDLES_OPEN);
|
||||
7
|
||||
8 g_signal_connect (app, "startup", G_CALLBACK (tfe_startup), NULL);
|
||||
9 g_signal_connect (app, "activate", G_CALLBACK (tfe_activate), NULL);
|
||||
10 g_signal_connect (app, "open", G_CALLBACK (tfe_open), NULL);
|
||||
11
|
||||
12 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
13 g_object_unref (app);
|
||||
14 return stat;
|
||||
15 }
|
||||
~~~
|
||||
|
||||
- 6: Generate GtkApplication object.
|
||||
- 8-10: Connect "startup", "activate" and "open signals to their handlers.
|
||||
|
@ -47,38 +49,40 @@ What the signal handler needs to do is initialization of the application.
|
|||
|
||||
The handler is as follows.
|
||||
|
||||
1 static void
|
||||
2 tfe_startup (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkApplicationWindow *win;
|
||||
5 GtkNotebook *nb;
|
||||
6 GtkBuilder *build;
|
||||
7 GtkButton *btno;
|
||||
8 GtkButton *btnn;
|
||||
9 GtkButton *btns;
|
||||
10 GtkButton *btnc;
|
||||
11
|
||||
12 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe/tfe.ui");
|
||||
13 win = GTK_APPLICATION_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
14 nb = GTK_NOTEBOOK (gtk_builder_get_object (build, "nb"));
|
||||
15 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
16 btno = GTK_BUTTON (gtk_builder_get_object (build, "btno"));
|
||||
17 btnn = GTK_BUTTON (gtk_builder_get_object (build, "btnn"));
|
||||
18 btns = GTK_BUTTON (gtk_builder_get_object (build, "btns"));
|
||||
19 btnc = GTK_BUTTON (gtk_builder_get_object (build, "btnc"));
|
||||
20 g_signal_connect (btno, "clicked", G_CALLBACK (open_clicked), nb);
|
||||
21 g_signal_connect (btnn, "clicked", G_CALLBACK (new_clicked), nb);
|
||||
22 g_signal_connect (btns, "clicked", G_CALLBACK (save_clicked), nb);
|
||||
23 g_signal_connect (btnc, "clicked", G_CALLBACK (close_clicked), nb);
|
||||
24 g_object_unref(build);
|
||||
25
|
||||
26 GdkDisplay *display;
|
||||
27
|
||||
28 display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
29 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
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);
|
||||
32 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 tfe_startup (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkApplicationWindow *win;
|
||||
5 GtkNotebook *nb;
|
||||
6 GtkBuilder *build;
|
||||
7 GtkButton *btno;
|
||||
8 GtkButton *btnn;
|
||||
9 GtkButton *btns;
|
||||
10 GtkButton *btnc;
|
||||
11
|
||||
12 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe/tfe.ui");
|
||||
13 win = GTK_APPLICATION_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
14 nb = GTK_NOTEBOOK (gtk_builder_get_object (build, "nb"));
|
||||
15 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
16 btno = GTK_BUTTON (gtk_builder_get_object (build, "btno"));
|
||||
17 btnn = GTK_BUTTON (gtk_builder_get_object (build, "btnn"));
|
||||
18 btns = GTK_BUTTON (gtk_builder_get_object (build, "btns"));
|
||||
19 btnc = GTK_BUTTON (gtk_builder_get_object (build, "btnc"));
|
||||
20 g_signal_connect (btno, "clicked", G_CALLBACK (open_clicked), nb);
|
||||
21 g_signal_connect (btnn, "clicked", G_CALLBACK (new_clicked), nb);
|
||||
22 g_signal_connect (btns, "clicked", G_CALLBACK (save_clicked), nb);
|
||||
23 g_signal_connect (btnc, "clicked", G_CALLBACK (close_clicked), nb);
|
||||
24 g_object_unref(build);
|
||||
25
|
||||
26 GdkDisplay *display;
|
||||
27
|
||||
28 display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
29 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
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);
|
||||
32 }
|
||||
~~~
|
||||
|
||||
- 12-15: Build widgets using ui file (resource).
|
||||
Connect the top window and the application using `gtk_window_set_application`.
|
||||
|
@ -168,39 +172,41 @@ CSS set to the context takes precedence over the one set to the display.
|
|||
The handler of "activate" and "open" signal are `tfe_activate` and `tfe_open` respectively.
|
||||
They just generate a new GtkNotebookPage.
|
||||
|
||||
1 static void
|
||||
2 tfe_activate (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkWidget *win;
|
||||
5 GtkWidget *boxv;
|
||||
6 GtkNotebook *nb;
|
||||
7
|
||||
8 win = GTK_WIDGET (gtk_application_get_active_window (app));
|
||||
9 boxv = gtk_window_get_child (GTK_WINDOW (win));
|
||||
10 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
11
|
||||
12 notebook_page_new (nb);
|
||||
13 gtk_widget_show (GTK_WIDGET (win));
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 tfe_open (GApplication *application, GFile ** files, gint n_files, const gchar *hint) {
|
||||
18 GtkApplication *app = GTK_APPLICATION (application);
|
||||
19 GtkWidget *win;
|
||||
20 GtkWidget *boxv;
|
||||
21 GtkNotebook *nb;
|
||||
22 int i;
|
||||
23
|
||||
24 win = GTK_WIDGET (gtk_application_get_active_window (app));
|
||||
25 boxv = gtk_window_get_child (GTK_WINDOW (win));
|
||||
26 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
27
|
||||
28 for (i = 0; i < n_files; i++)
|
||||
29 notebook_page_new_with_file (nb, files[i]);
|
||||
30 if (gtk_notebook_get_n_pages (nb) == 0)
|
||||
31 notebook_page_new (nb);
|
||||
32 gtk_widget_show (win);
|
||||
33 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 tfe_activate (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkWidget *win;
|
||||
5 GtkWidget *boxv;
|
||||
6 GtkNotebook *nb;
|
||||
7
|
||||
8 win = GTK_WIDGET (gtk_application_get_active_window (app));
|
||||
9 boxv = gtk_window_get_child (GTK_WINDOW (win));
|
||||
10 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
11
|
||||
12 notebook_page_new (nb);
|
||||
13 gtk_widget_show (GTK_WIDGET (win));
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 tfe_open (GApplication *application, GFile ** files, gint n_files, const gchar *hint) {
|
||||
18 GtkApplication *app = GTK_APPLICATION (application);
|
||||
19 GtkWidget *win;
|
||||
20 GtkWidget *boxv;
|
||||
21 GtkNotebook *nb;
|
||||
22 int i;
|
||||
23
|
||||
24 win = GTK_WIDGET (gtk_application_get_active_window (app));
|
||||
25 boxv = gtk_window_get_child (GTK_WINDOW (win));
|
||||
26 nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
27
|
||||
28 for (i = 0; i < n_files; i++)
|
||||
29 notebook_page_new_with_file (nb, files[i]);
|
||||
30 if (gtk_notebook_get_n_pages (nb) == 0)
|
||||
31 notebook_page_new (nb);
|
||||
32 gtk_widget_show (win);
|
||||
33 }
|
||||
~~~
|
||||
|
||||
- 1-14: `tfe_activate`.
|
||||
- 8-10: Get GtkNotebook object.
|
||||
|
@ -249,36 +255,38 @@ The second instance immediately quits so shell prompt soon appears.
|
|||
|
||||
## a series of handlers correspond to the button signals
|
||||
|
||||
1 static void
|
||||
2 open_clicked (GtkWidget *btno, GtkNotebook *nb) {
|
||||
3 notebook_page_open (nb);
|
||||
4 }
|
||||
5
|
||||
6 static void
|
||||
7 new_clicked (GtkWidget *btnn, GtkNotebook *nb) {
|
||||
8 notebook_page_new (nb);
|
||||
9 }
|
||||
10
|
||||
11 static void
|
||||
12 save_clicked (GtkWidget *btns, GtkNotebook *nb) {
|
||||
13 notebook_page_save (nb);
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 close_clicked (GtkWidget *btnc, GtkNotebook *nb) {
|
||||
18 GtkWidget *win;
|
||||
19 GtkWidget *boxv;
|
||||
20 gint i;
|
||||
21
|
||||
22 if (gtk_notebook_get_n_pages (nb) == 1) {
|
||||
23 boxv = gtk_widget_get_parent (GTK_WIDGET (nb));
|
||||
24 win = gtk_widget_get_parent (boxv);
|
||||
25 gtk_window_destroy (GTK_WINDOW (win));
|
||||
26 } else {
|
||||
27 i = gtk_notebook_get_current_page (nb);
|
||||
28 gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
|
||||
29 }
|
||||
30 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 open_clicked (GtkWidget *btno, GtkNotebook *nb) {
|
||||
3 notebook_page_open (nb);
|
||||
4 }
|
||||
5
|
||||
6 static void
|
||||
7 new_clicked (GtkWidget *btnn, GtkNotebook *nb) {
|
||||
8 notebook_page_new (nb);
|
||||
9 }
|
||||
10
|
||||
11 static void
|
||||
12 save_clicked (GtkWidget *btns, GtkNotebook *nb) {
|
||||
13 notebook_page_save (nb);
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 close_clicked (GtkWidget *btnc, GtkNotebook *nb) {
|
||||
18 GtkWidget *win;
|
||||
19 GtkWidget *boxv;
|
||||
20 gint i;
|
||||
21
|
||||
22 if (gtk_notebook_get_n_pages (nb) == 1) {
|
||||
23 boxv = gtk_widget_get_parent (GTK_WIDGET (nb));
|
||||
24 win = gtk_widget_get_parent (boxv);
|
||||
25 gtk_window_destroy (GTK_WINDOW (win));
|
||||
26 } else {
|
||||
27 i = gtk_notebook_get_current_page (nb);
|
||||
28 gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
|
||||
29 }
|
||||
30 }
|
||||
~~~
|
||||
|
||||
`open_clicked`, `new_clicked` and `save_clicked` just call corresponding notebook page functions.
|
||||
`close_clicked` is a bit complicated.
|
||||
|
@ -289,16 +297,18 @@ First, get the top level window and call `gtk_window_destroy`.
|
|||
|
||||
## meson.build
|
||||
|
||||
1 project('tfe', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','tfe.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~meson
|
||||
1 project('tfe', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','tfe.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~
|
||||
|
||||
In this file, just the source file names are modified.
|
||||
|
||||
|
|
1170
gfm/sec15.md
1170
gfm/sec15.md
File diff suppressed because it is too large
Load diff
96
gfm/sec16.md
96
gfm/sec16.md
|
@ -119,53 +119,55 @@ So, if the action is activated, the handler will be invoked.
|
|||
|
||||
The following is a simple example of menus and actions.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
5 {
|
||||
6 g_application_quit (G_APPLICATION(app));
|
||||
7 }
|
||||
8
|
||||
9 static void
|
||||
10 on_activate (GApplication *app, gpointer user_data) {
|
||||
11 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
12 gtk_window_set_title (GTK_WINDOW (win), "menu1");
|
||||
13 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
14
|
||||
15 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
|
||||
16 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
17 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
18
|
||||
19 GMenu *menubar = g_menu_new ();
|
||||
20 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
|
||||
21 GMenu *menu = g_menu_new ();
|
||||
22 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
23 g_menu_append_item (menu, menu_item_quit);
|
||||
24 g_object_unref (menu_item_quit);
|
||||
25 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
|
||||
26 g_menu_append_item (menubar, menu_item_menu);
|
||||
27 g_object_unref (menu_item_menu);
|
||||
28
|
||||
29 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
30 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
31 gtk_window_present (GTK_WINDOW (win));
|
||||
32 /* gtk_widget_show (win); is also OKay instead of gtk_window_present. */
|
||||
33 }
|
||||
34
|
||||
35 int
|
||||
36 main (int argc, char **argv) {
|
||||
37 GtkApplication *app;
|
||||
38 int stat;
|
||||
39
|
||||
40 app = gtk_application_new ("com.github.ToshioCP.menu1", G_APPLICATION_FLAGS_NONE);
|
||||
41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
42
|
||||
43 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
44 g_object_unref (app);
|
||||
45 return stat;
|
||||
46 }
|
||||
47
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
5 {
|
||||
6 g_application_quit (G_APPLICATION(app));
|
||||
7 }
|
||||
8
|
||||
9 static void
|
||||
10 on_activate (GApplication *app, gpointer user_data) {
|
||||
11 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
12 gtk_window_set_title (GTK_WINDOW (win), "menu1");
|
||||
13 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
14
|
||||
15 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
|
||||
16 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
17 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
18
|
||||
19 GMenu *menubar = g_menu_new ();
|
||||
20 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
|
||||
21 GMenu *menu = g_menu_new ();
|
||||
22 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
23 g_menu_append_item (menu, menu_item_quit);
|
||||
24 g_object_unref (menu_item_quit);
|
||||
25 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
|
||||
26 g_menu_append_item (menubar, menu_item_menu);
|
||||
27 g_object_unref (menu_item_menu);
|
||||
28
|
||||
29 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
30 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
31 gtk_window_present (GTK_WINDOW (win));
|
||||
32 /* gtk_widget_show (win); is also OKay instead of gtk_window_present. */
|
||||
33 }
|
||||
34
|
||||
35 int
|
||||
36 main (int argc, char **argv) {
|
||||
37 GtkApplication *app;
|
||||
38 int stat;
|
||||
39
|
||||
40 app = gtk_application_new ("com.github.ToshioCP.menu1", G_APPLICATION_FLAGS_NONE);
|
||||
41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
42
|
||||
43 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
44 g_object_unref (app);
|
||||
45 return stat;
|
||||
46 }
|
||||
47
|
||||
~~~
|
||||
|
||||
- 3-7: `quit_activated` is a handler of an action `act_quit`.
|
||||
Handlers of actions have three parameters.
|
||||
|
|
239
gfm/sec17.md
239
gfm/sec17.md
|
@ -21,7 +21,8 @@ The signal handler will be described after the explanation of this code.
|
|||
static void
|
||||
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");
|
||||
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
|
||||
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_green = g_menu_item_new ("Green", "win.color::green");
|
||||
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
|
||||
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);
|
||||
g_free (color);
|
||||
g_action_change_state (G_ACTION (action), parameter);
|
||||
|
@ -187,14 +190,16 @@ When GVariantType is generated, the type is expressed by the string.
|
|||
The following program is a simple example.
|
||||
It finally output the string "s".
|
||||
|
||||
1 #include <glib.h>
|
||||
2
|
||||
3 int
|
||||
4 main (int argc, char **argv) {
|
||||
5 GVariantType *vtype = g_variant_type_new ("s");
|
||||
6 const gchar *type_string = g_variant_type_peek_string (vtype);
|
||||
7 g_print ("%s\n",type_string);
|
||||
8 }
|
||||
~~~C
|
||||
1 #include <glib.h>
|
||||
2
|
||||
3 int
|
||||
4 main (int argc, char **argv) {
|
||||
5 GVariantType *vtype = g_variant_type_new ("s");
|
||||
6 const gchar *type_string = g_variant_type_peek_string (vtype);
|
||||
7 g_print ("%s\n",type_string);
|
||||
8 }
|
||||
~~~
|
||||
|
||||
- `g_variant_tpe_new` generates GVariantType.
|
||||
It uses a type string "s" which means string.
|
||||
|
@ -217,111 +222,113 @@ And the radio button of the selected menu turns on.
|
|||
|
||||
The code is as follows.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static GtkCssProvider *provider;
|
||||
4
|
||||
5 static void
|
||||
6 fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
7 if (g_variant_get_boolean (value))
|
||||
8 gtk_window_maximize (GTK_WINDOW (win));
|
||||
9 else
|
||||
10 gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
11 g_simple_action_set_state (action, value);
|
||||
12 }
|
||||
13
|
||||
14 static void
|
||||
15 color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
16 gchar *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
17 gtk_css_provider_load_from_data (provider, color, -1);
|
||||
18 g_free (color);
|
||||
19 g_action_change_state (G_ACTION (action), parameter);
|
||||
20 }
|
||||
21
|
||||
22 static void
|
||||
23 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
24 {
|
||||
25 g_application_quit (G_APPLICATION(app));
|
||||
26 }
|
||||
27
|
||||
28 static void
|
||||
29 on_activate (GApplication *app, gpointer user_data) {
|
||||
30 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
31 gtk_window_set_title (GTK_WINDOW (win), "menu2");
|
||||
32 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
33
|
||||
34 GtkWidget *lb = gtk_label_new (NULL);
|
||||
35 gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */
|
||||
36 gtk_window_set_child (GTK_WINDOW (win), lb);
|
||||
37
|
||||
38 GSimpleAction *act_fullscreen
|
||||
39 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
40 GSimpleAction *act_color
|
||||
41 = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
42 GSimpleAction *act_quit
|
||||
43 = g_simple_action_new ("quit", NULL);
|
||||
44
|
||||
45 GMenu *menubar = g_menu_new ();
|
||||
46 GMenu *menu = g_menu_new ();
|
||||
47 GMenu *section1 = g_menu_new ();
|
||||
48 GMenu *section2 = g_menu_new ();
|
||||
49 GMenu *section3 = g_menu_new ();
|
||||
50 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
51 GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
|
||||
52 GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
|
||||
53 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
|
||||
54 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
55
|
||||
56 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
57 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
58 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
59 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
60 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color));
|
||||
61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
62
|
||||
63 g_menu_append_item (section1, menu_item_fullscreen);
|
||||
64 g_menu_append_item (section2, menu_item_red);
|
||||
65 g_menu_append_item (section2, menu_item_green);
|
||||
66 g_menu_append_item (section2, menu_item_blue);
|
||||
67 g_menu_append_item (section3, menu_item_quit);
|
||||
68 g_object_unref (menu_item_red);
|
||||
69 g_object_unref (menu_item_green);
|
||||
70 g_object_unref (menu_item_blue);
|
||||
71 g_object_unref (menu_item_fullscreen);
|
||||
72 g_object_unref (menu_item_quit);
|
||||
73
|
||||
74 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
|
||||
75 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
|
||||
76 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
|
||||
77 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
78
|
||||
79 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
80 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
81
|
||||
82 /* GtkCssProvider *provider = gtk_css_provider_new ();*/
|
||||
83 provider = gtk_css_provider_new ();
|
||||
84 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
85 gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1);
|
||||
86 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
87 GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
88
|
||||
89 /* gtk_widget_show (win);*/
|
||||
90 gtk_window_present (GTK_WINDOW (win));
|
||||
91 }
|
||||
92
|
||||
93 int
|
||||
94 main (int argc, char **argv) {
|
||||
95 GtkApplication *app;
|
||||
96 int stat;
|
||||
97
|
||||
98 app = gtk_application_new ("com.github.ToshioCP.menu2", G_APPLICATION_FLAGS_NONE);
|
||||
99 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
100
|
||||
101 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
102 g_object_unref (app);
|
||||
103 return stat;
|
||||
104 }
|
||||
105
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static GtkCssProvider *provider;
|
||||
4
|
||||
5 static void
|
||||
6 fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
7 if (g_variant_get_boolean (value))
|
||||
8 gtk_window_maximize (GTK_WINDOW (win));
|
||||
9 else
|
||||
10 gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
11 g_simple_action_set_state (action, value);
|
||||
12 }
|
||||
13
|
||||
14 static void
|
||||
15 color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
16 gchar *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
17 gtk_css_provider_load_from_data (provider, color, -1);
|
||||
18 g_free (color);
|
||||
19 g_action_change_state (G_ACTION (action), parameter);
|
||||
20 }
|
||||
21
|
||||
22 static void
|
||||
23 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
24 {
|
||||
25 g_application_quit (G_APPLICATION(app));
|
||||
26 }
|
||||
27
|
||||
28 static void
|
||||
29 on_activate (GApplication *app, gpointer user_data) {
|
||||
30 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
31 gtk_window_set_title (GTK_WINDOW (win), "menu2");
|
||||
32 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
33
|
||||
34 GtkWidget *lb = gtk_label_new (NULL);
|
||||
35 gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */
|
||||
36 gtk_window_set_child (GTK_WINDOW (win), lb);
|
||||
37
|
||||
38 GSimpleAction *act_fullscreen
|
||||
39 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
40 GSimpleAction *act_color
|
||||
41 = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
42 GSimpleAction *act_quit
|
||||
43 = g_simple_action_new ("quit", NULL);
|
||||
44
|
||||
45 GMenu *menubar = g_menu_new ();
|
||||
46 GMenu *menu = g_menu_new ();
|
||||
47 GMenu *section1 = g_menu_new ();
|
||||
48 GMenu *section2 = g_menu_new ();
|
||||
49 GMenu *section3 = g_menu_new ();
|
||||
50 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
51 GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
|
||||
52 GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
|
||||
53 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
|
||||
54 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
55
|
||||
56 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
57 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
58 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
59 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
60 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color));
|
||||
61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
62
|
||||
63 g_menu_append_item (section1, menu_item_fullscreen);
|
||||
64 g_menu_append_item (section2, menu_item_red);
|
||||
65 g_menu_append_item (section2, menu_item_green);
|
||||
66 g_menu_append_item (section2, menu_item_blue);
|
||||
67 g_menu_append_item (section3, menu_item_quit);
|
||||
68 g_object_unref (menu_item_red);
|
||||
69 g_object_unref (menu_item_green);
|
||||
70 g_object_unref (menu_item_blue);
|
||||
71 g_object_unref (menu_item_fullscreen);
|
||||
72 g_object_unref (menu_item_quit);
|
||||
73
|
||||
74 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
|
||||
75 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
|
||||
76 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
|
||||
77 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
78
|
||||
79 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
80 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
81
|
||||
82 /* GtkCssProvider *provider = gtk_css_provider_new ();*/
|
||||
83 provider = gtk_css_provider_new ();
|
||||
84 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
85 gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1);
|
||||
86 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
87 GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
88
|
||||
89 /* gtk_widget_show (win);*/
|
||||
90 gtk_window_present (GTK_WINDOW (win));
|
||||
91 }
|
||||
92
|
||||
93 int
|
||||
94 main (int argc, char **argv) {
|
||||
95 GtkApplication *app;
|
||||
96 int stat;
|
||||
97
|
||||
98 app = gtk_application_new ("com.github.ToshioCP.menu2", G_APPLICATION_FLAGS_NONE);
|
||||
99 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
100
|
||||
101 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
102 g_object_unref (app);
|
||||
103 return stat;
|
||||
104 }
|
||||
105
|
||||
~~~
|
||||
|
||||
- 5-26: Signal handlers.
|
||||
They have been explained in this section.
|
||||
|
|
519
gfm/sec18.md
519
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
|
||||
|
||||
|
@ -13,22 +13,26 @@ The same goes for menus.
|
|||
The ui file for menus has interface, menu tags.
|
||||
The file starts and ends with interface tag.
|
||||
|
||||
<interface>
|
||||
<menu id="menubar">
|
||||
</menu>
|
||||
</interface>
|
||||
~~~xml
|
||||
<interface>
|
||||
<menu id="menubar">
|
||||
</menu>
|
||||
</interface>
|
||||
~~~
|
||||
|
||||
`menu` tag corresponds to GMenu object.
|
||||
`id` attribute defines the name of the object.
|
||||
It will be refered by GtkBuilder.
|
||||
|
||||
<submenu>
|
||||
<attribute name="label">File</attribute>
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</submenu>
|
||||
~~~xml
|
||||
<submenu>
|
||||
<attribute name="label">File</attribute>
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</submenu>
|
||||
~~~
|
||||
|
||||
`item` tag corresponds to item in GMenu which has the same structure as GMenuItem.
|
||||
The item above has a label attribute.
|
||||
|
@ -40,15 +44,17 @@ The GMenuItem has a link to GMenu.
|
|||
|
||||
The ui file above can be described as follows.
|
||||
|
||||
<item>
|
||||
<attribute name="label">File</attribute>
|
||||
<link name="submenu">
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
~~~xml
|
||||
<item>
|
||||
<attribute name="label">File</attribute>
|
||||
<link name="submenu">
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
~~~
|
||||
|
||||
`link` tag expresses the link to submenu.
|
||||
And at the same time it also expresses the submenu itself.
|
||||
|
@ -63,95 +69,101 @@ Its name is `menu3`.
|
|||
|
||||
The following is the ui file of the menu in `menu3`.
|
||||
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <interface>
|
||||
3 <menu id="menubar">
|
||||
4 <submenu>
|
||||
5 <attribute name="label">File</attribute>
|
||||
6 <section>
|
||||
7 <item>
|
||||
8 <attribute name="label">New</attribute>
|
||||
9 <attribute name="action">win.new</attribute>
|
||||
10 </item>
|
||||
11 <item>
|
||||
12 <attribute name="label">Open</attribute>
|
||||
13 <attribute name="action">win.open</attribute>
|
||||
14 </item>
|
||||
15 </section>
|
||||
16 <section>
|
||||
17 <item>
|
||||
18 <attribute name="label">Save</attribute>
|
||||
19 <attribute name="action">win.save</attribute>
|
||||
20 </item>
|
||||
21 <item>
|
||||
22 <attribute name="label">Save As…</attribute>
|
||||
23 <attribute name="action">win.saveas</attribute>
|
||||
24 </item>
|
||||
25 </section>
|
||||
26 <section>
|
||||
27 <item>
|
||||
28 <attribute name="label">Close</attribute>
|
||||
29 <attribute name="action">win.close</attribute>
|
||||
30 </item>
|
||||
31 </section>
|
||||
32 <section>
|
||||
33 <item>
|
||||
34 <attribute name="label">Quit</attribute>
|
||||
35 <attribute name="action">app.quit</attribute>
|
||||
36 </item>
|
||||
37 </section>
|
||||
38 </submenu>
|
||||
39 <submenu>
|
||||
40 <attribute name="label">Edit</attribute>
|
||||
41 <section>
|
||||
42 <item>
|
||||
43 <attribute name="label">Cut</attribute>
|
||||
44 <attribute name="action">win.cut</attribute>
|
||||
45 </item>
|
||||
46 <item>
|
||||
47 <attribute name="label">Copy</attribute>
|
||||
48 <attribute name="action">win.copy</attribute>
|
||||
49 </item>
|
||||
50 <item>
|
||||
51 <attribute name="label">Paste</attribute>
|
||||
52 <attribute name="action">win.paste</attribute>
|
||||
53 </item>
|
||||
54 </section>
|
||||
55 <section>
|
||||
56 <item>
|
||||
57 <attribute name="label">Select All</attribute>
|
||||
58 <attribute name="action">win.selectall</attribute>
|
||||
59 </item>
|
||||
60 </section>
|
||||
61 </submenu>
|
||||
62 <submenu>
|
||||
63 <attribute name="label">View</attribute>
|
||||
64 <section>
|
||||
65 <item>
|
||||
66 <attribute name="label">Full Screen</attribute>
|
||||
67 <attribute name="action">win.fullscreen</attribute>
|
||||
68 </item>
|
||||
69 </section>
|
||||
70 </submenu>
|
||||
71 </menu>
|
||||
72 </interface>
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <interface>
|
||||
3 <menu id="menubar">
|
||||
4 <submenu>
|
||||
5 <attribute name="label">File</attribute>
|
||||
6 <section>
|
||||
7 <item>
|
||||
8 <attribute name="label">New</attribute>
|
||||
9 <attribute name="action">win.new</attribute>
|
||||
10 </item>
|
||||
11 <item>
|
||||
12 <attribute name="label">Open</attribute>
|
||||
13 <attribute name="action">win.open</attribute>
|
||||
14 </item>
|
||||
15 </section>
|
||||
16 <section>
|
||||
17 <item>
|
||||
18 <attribute name="label">Save</attribute>
|
||||
19 <attribute name="action">win.save</attribute>
|
||||
20 </item>
|
||||
21 <item>
|
||||
22 <attribute name="label">Save As…</attribute>
|
||||
23 <attribute name="action">win.saveas</attribute>
|
||||
24 </item>
|
||||
25 </section>
|
||||
26 <section>
|
||||
27 <item>
|
||||
28 <attribute name="label">Close</attribute>
|
||||
29 <attribute name="action">win.close</attribute>
|
||||
30 </item>
|
||||
31 </section>
|
||||
32 <section>
|
||||
33 <item>
|
||||
34 <attribute name="label">Quit</attribute>
|
||||
35 <attribute name="action">app.quit</attribute>
|
||||
36 </item>
|
||||
37 </section>
|
||||
38 </submenu>
|
||||
39 <submenu>
|
||||
40 <attribute name="label">Edit</attribute>
|
||||
41 <section>
|
||||
42 <item>
|
||||
43 <attribute name="label">Cut</attribute>
|
||||
44 <attribute name="action">win.cut</attribute>
|
||||
45 </item>
|
||||
46 <item>
|
||||
47 <attribute name="label">Copy</attribute>
|
||||
48 <attribute name="action">win.copy</attribute>
|
||||
49 </item>
|
||||
50 <item>
|
||||
51 <attribute name="label">Paste</attribute>
|
||||
52 <attribute name="action">win.paste</attribute>
|
||||
53 </item>
|
||||
54 </section>
|
||||
55 <section>
|
||||
56 <item>
|
||||
57 <attribute name="label">Select All</attribute>
|
||||
58 <attribute name="action">win.selectall</attribute>
|
||||
59 </item>
|
||||
60 </section>
|
||||
61 </submenu>
|
||||
62 <submenu>
|
||||
63 <attribute name="label">View</attribute>
|
||||
64 <section>
|
||||
65 <item>
|
||||
66 <attribute name="label">Full Screen</attribute>
|
||||
67 <attribute name="action">win.fullscreen</attribute>
|
||||
68 </item>
|
||||
69 </section>
|
||||
70 </submenu>
|
||||
71 </menu>
|
||||
72 </interface>
|
||||
~~~
|
||||
|
||||
The ui file is converted to the resource by the resouce compiler `glib-compile-resouces` with xml file below.
|
||||
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/menu3">
|
||||
4 <file>menu3.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/menu3">
|
||||
4 <file>menu3.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~
|
||||
|
||||
GtkBuilder builds menus from the resource.
|
||||
|
||||
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
~~~C
|
||||
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
g_object_unref (builder);
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
g_object_unref (builder);
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
typedef struct _GActionEntry GActionEntry;
|
||||
|
||||
struct _GActionEntry
|
||||
{
|
||||
const gchar *name; /* action name */
|
||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data); /* activate handler */
|
||||
const gchar *parameter_type; /* the type of the parameter given as a single GVariant type string */
|
||||
const gchar *state; /* initial state given in GVariant text format */
|
||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data); /* change-state handler */
|
||||
/*< private >*/
|
||||
gsize padding[3];
|
||||
};
|
||||
~~~C
|
||||
typedef struct _GActionEntry GActionEntry;
|
||||
|
||||
struct _GActionEntry
|
||||
{
|
||||
/* action name */
|
||||
const gchar *name;
|
||||
/* activate handler */
|
||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
|
||||
/* the type of the parameter given as a single GVariant type string */
|
||||
const gchar *parameter_type;
|
||||
/* initial state given in GVariant text format */
|
||||
const gchar *state;
|
||||
/* change-state handler */
|
||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);
|
||||
/*< private >*/
|
||||
gsize padding[3];
|
||||
};
|
||||
~~~
|
||||
For example, the actions in the previous section are:
|
||||
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
~~~C
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
~~~
|
||||
|
||||
And `g_action_map_add_action_entries` does all the process instead of the functions you have needed.
|
||||
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
~~~C
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
|
||||
G_N_ELEMENTS (app_entries), app);
|
||||
~~~
|
||||
|
||||
The code above does:
|
||||
|
||||
|
@ -198,12 +221,14 @@ The code above does:
|
|||
|
||||
The same goes for the other actions.
|
||||
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
|
||||
~~~C
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,
|
||||
G_N_ELEMENTS (win_entries), win);
|
||||
~~~
|
||||
The code above does:
|
||||
|
||||
- Build a "fullscreen" action and "color" action.
|
||||
|
@ -217,125 +242,129 @@ The code above does:
|
|||
|
||||
The C source code of `menu3` and `meson.build` is as follows.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
5 }
|
||||
6
|
||||
7 static void
|
||||
8 open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
9 }
|
||||
10
|
||||
11 static void
|
||||
12 save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
13 }
|
||||
14
|
||||
15 static void
|
||||
16 saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
17 }
|
||||
18
|
||||
19 static void
|
||||
20 close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
21 }
|
||||
22
|
||||
23 static void
|
||||
24 cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
25 }
|
||||
26
|
||||
27 static void
|
||||
28 copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
29 }
|
||||
30
|
||||
31 static void
|
||||
32 paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
33 }
|
||||
34
|
||||
35 static void
|
||||
36 selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
37 }
|
||||
38
|
||||
39 static void
|
||||
40 fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) {
|
||||
41 if (g_variant_get_boolean (state))
|
||||
42 gtk_window_maximize (GTK_WINDOW (win));
|
||||
43 else
|
||||
44 gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
45 g_simple_action_set_state (action, state);
|
||||
46 }
|
||||
47
|
||||
48 static void
|
||||
49 quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
50 {
|
||||
51 g_application_quit (G_APPLICATION(app));
|
||||
52 }
|
||||
53
|
||||
54 static void
|
||||
55 on_activate (GApplication *app, gpointer user_data) {
|
||||
56 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
57
|
||||
58 const GActionEntry win_entries[] = {
|
||||
59 { "new", new_activated, NULL, NULL, NULL },
|
||||
60 { "open", open_activated, NULL, NULL, NULL },
|
||||
61 { "save", save_activated, NULL, NULL, NULL },
|
||||
62 { "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
63 { "close", close_activated, NULL, NULL, NULL },
|
||||
64 { "cut", cut_activated, NULL, NULL, NULL },
|
||||
65 { "copy", copy_activated, NULL, NULL, NULL },
|
||||
66 { "paste", paste_activated, NULL, NULL, NULL },
|
||||
67 { "selectall", selectall_activated, NULL, NULL, NULL },
|
||||
68 { "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
69 };
|
||||
70 g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
71
|
||||
72 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
73
|
||||
74 gtk_window_set_title (GTK_WINDOW (win), "menu3");
|
||||
75 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
76 gtk_widget_show (win);
|
||||
77 }
|
||||
78
|
||||
79 static void
|
||||
80 on_startup (GApplication *app, gpointer user_data) {
|
||||
81 GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
82 GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
83
|
||||
84 gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
85 g_object_unref (builder);
|
||||
86
|
||||
87 const GActionEntry app_entries[] = {
|
||||
88 { "quit", quit_activated, NULL, NULL, NULL }
|
||||
89 };
|
||||
90 g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
91 }
|
||||
92
|
||||
93 int
|
||||
94 main (int argc, char **argv) {
|
||||
95 GtkApplication *app;
|
||||
96 int stat;
|
||||
97
|
||||
98 app = gtk_application_new ("com.github.ToshioCP.menu3", G_APPLICATION_FLAGS_NONE);
|
||||
99 g_signal_connect (app, "startup", G_CALLBACK (on_startup), NULL);
|
||||
100 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
101
|
||||
102 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
103 g_object_unref (app);
|
||||
104 return stat;
|
||||
105 }
|
||||
106
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
5 }
|
||||
6
|
||||
7 static void
|
||||
8 open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
9 }
|
||||
10
|
||||
11 static void
|
||||
12 save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
13 }
|
||||
14
|
||||
15 static void
|
||||
16 saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
17 }
|
||||
18
|
||||
19 static void
|
||||
20 close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
21 }
|
||||
22
|
||||
23 static void
|
||||
24 cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
25 }
|
||||
26
|
||||
27 static void
|
||||
28 copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
29 }
|
||||
30
|
||||
31 static void
|
||||
32 paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
33 }
|
||||
34
|
||||
35 static void
|
||||
36 selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
37 }
|
||||
38
|
||||
39 static void
|
||||
40 fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) {
|
||||
41 if (g_variant_get_boolean (state))
|
||||
42 gtk_window_maximize (GTK_WINDOW (win));
|
||||
43 else
|
||||
44 gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
45 g_simple_action_set_state (action, state);
|
||||
46 }
|
||||
47
|
||||
48 static void
|
||||
49 quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
50 {
|
||||
51 g_application_quit (G_APPLICATION(app));
|
||||
52 }
|
||||
53
|
||||
54 static void
|
||||
55 on_activate (GApplication *app, gpointer user_data) {
|
||||
56 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
57
|
||||
58 const GActionEntry win_entries[] = {
|
||||
59 { "new", new_activated, NULL, NULL, NULL },
|
||||
60 { "open", open_activated, NULL, NULL, NULL },
|
||||
61 { "save", save_activated, NULL, NULL, NULL },
|
||||
62 { "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
63 { "close", close_activated, NULL, NULL, NULL },
|
||||
64 { "cut", cut_activated, NULL, NULL, NULL },
|
||||
65 { "copy", copy_activated, NULL, NULL, NULL },
|
||||
66 { "paste", paste_activated, NULL, NULL, NULL },
|
||||
67 { "selectall", selectall_activated, NULL, NULL, NULL },
|
||||
68 { "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
69 };
|
||||
70 g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
71
|
||||
72 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
73
|
||||
74 gtk_window_set_title (GTK_WINDOW (win), "menu3");
|
||||
75 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
76 gtk_widget_show (win);
|
||||
77 }
|
||||
78
|
||||
79 static void
|
||||
80 on_startup (GApplication *app, gpointer user_data) {
|
||||
81 GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
82 GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
83
|
||||
84 gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
85 g_object_unref (builder);
|
||||
86
|
||||
87 const GActionEntry app_entries[] = {
|
||||
88 { "quit", quit_activated, NULL, NULL, NULL }
|
||||
89 };
|
||||
90 g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
91 }
|
||||
92
|
||||
93 int
|
||||
94 main (int argc, char **argv) {
|
||||
95 GtkApplication *app;
|
||||
96 int stat;
|
||||
97
|
||||
98 app = gtk_application_new ("com.github.ToshioCP.menu3", G_APPLICATION_FLAGS_NONE);
|
||||
99 g_signal_connect (app, "startup", G_CALLBACK (on_startup), NULL);
|
||||
100 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
101
|
||||
102 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
103 g_object_unref (app);
|
||||
104 return stat;
|
||||
105 }
|
||||
106
|
||||
~~~
|
||||
|
||||
meson.build
|
||||
|
||||
1 project('menu3', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','menu3.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('menu3.c')
|
||||
9
|
||||
10 executable('menu3', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~meson
|
||||
1 project('menu3', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','menu3.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('menu3.c')
|
||||
9
|
||||
10 executable('menu3', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~
|
||||
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 17](sec17.md)
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 17](sec17.md), Next: [Section 19](sec19.md)
|
||||
|
|
148
gfm/sec19.md
148
gfm/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
|
||||
|
||||
|
@ -46,37 +46,39 @@ This will be a destnation.
|
|||
|
||||
Here's a simple example code that draws a small square and save it as a png file.
|
||||
|
||||
1 #include <cairo.h>
|
||||
2
|
||||
3 int
|
||||
4 main (int argc, char **argv)
|
||||
5 {
|
||||
6 cairo_surface_t *surface;
|
||||
7 cairo_t *cr;
|
||||
8 int width = 100;
|
||||
9 int height = 100;
|
||||
10
|
||||
11 /* Generate surface and cairo */
|
||||
12 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
||||
13 cr = cairo_create (surface);
|
||||
14
|
||||
15 /* Drawing starts here. */
|
||||
16 /* Paint the background white */
|
||||
17 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
||||
18 cairo_paint (cr);
|
||||
19 /* Draw a black rectangle */
|
||||
20 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
||||
21 cairo_set_line_width (cr, 2.0);
|
||||
22 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0);
|
||||
23 cairo_stroke (cr);
|
||||
24
|
||||
25 /* Write the surface to a png file and clean up cairo and surface. */
|
||||
26 cairo_surface_write_to_png (surface, "rectangle.png");
|
||||
27 cairo_destroy (cr);
|
||||
28 cairo_surface_destroy (surface);
|
||||
29
|
||||
30 return 0;
|
||||
31 }
|
||||
~~~C
|
||||
1 #include <cairo.h>
|
||||
2
|
||||
3 int
|
||||
4 main (int argc, char **argv)
|
||||
5 {
|
||||
6 cairo_surface_t *surface;
|
||||
7 cairo_t *cr;
|
||||
8 int width = 100;
|
||||
9 int height = 100;
|
||||
10
|
||||
11 /* Generate surface and cairo */
|
||||
12 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
||||
13 cr = cairo_create (surface);
|
||||
14
|
||||
15 /* Drawing starts here. */
|
||||
16 /* Paint the background white */
|
||||
17 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
||||
18 cairo_paint (cr);
|
||||
19 /* Draw a black rectangle */
|
||||
20 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
||||
21 cairo_set_line_width (cr, 2.0);
|
||||
22 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0);
|
||||
23 cairo_stroke (cr);
|
||||
24
|
||||
25 /* Write the surface to a png file and clean up cairo and surface. */
|
||||
26 cairo_surface_write_to_png (surface, "rectangle.png");
|
||||
27 cairo_destroy (cr);
|
||||
28 cairo_surface_destroy (surface);
|
||||
29
|
||||
30 return 0;
|
||||
31 }
|
||||
~~~
|
||||
|
||||
- 1: Include the header file of cairo.
|
||||
- 12: `cairo_image_surface_create` creates an image surface.
|
||||
|
@ -117,45 +119,47 @@ If you aren't familiar with cairo, it is strongly recommended to read the [tutor
|
|||
|
||||
The following is a very simple example.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
5 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* whilte */
|
||||
6 cairo_paint (cr);
|
||||
7 cairo_set_line_width (cr, 2.0);
|
||||
8 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
|
||||
9 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0);
|
||||
10 cairo_stroke (cr);
|
||||
11 }
|
||||
12
|
||||
13 static void
|
||||
14 on_activate (GApplication *app, gpointer user_data) {
|
||||
15 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
16 GtkWidget *area = gtk_drawing_area_new ();
|
||||
17
|
||||
18 gtk_window_set_title (GTK_WINDOW (win), "da1");
|
||||
19 /* Set initial size of width and height */
|
||||
20 gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 100);
|
||||
21 gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 100);
|
||||
22 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
|
||||
23 gtk_window_set_child (GTK_WINDOW (win), area);
|
||||
24
|
||||
25 gtk_widget_show (win);
|
||||
26 }
|
||||
27
|
||||
28 int
|
||||
29 main (int argc, char **argv) {
|
||||
30 GtkApplication *app;
|
||||
31 int stat;
|
||||
32
|
||||
33 app = gtk_application_new ("com.github.ToshioCP.da1", G_APPLICATION_FLAGS_NONE);
|
||||
34 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
35 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
36 g_object_unref (app);
|
||||
37 return stat;
|
||||
38 }
|
||||
39
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
5 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* whilte */
|
||||
6 cairo_paint (cr);
|
||||
7 cairo_set_line_width (cr, 2.0);
|
||||
8 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
|
||||
9 cairo_rectangle (cr, width/2.0 - 20.0, height/2.0 - 20.0, 40.0, 40.0);
|
||||
10 cairo_stroke (cr);
|
||||
11 }
|
||||
12
|
||||
13 static void
|
||||
14 on_activate (GApplication *app, gpointer user_data) {
|
||||
15 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
16 GtkWidget *area = gtk_drawing_area_new ();
|
||||
17
|
||||
18 gtk_window_set_title (GTK_WINDOW (win), "da1");
|
||||
19 /* Set initial size of width and height */
|
||||
20 gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 100);
|
||||
21 gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 100);
|
||||
22 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
|
||||
23 gtk_window_set_child (GTK_WINDOW (win), area);
|
||||
24
|
||||
25 gtk_widget_show (win);
|
||||
26 }
|
||||
27
|
||||
28 int
|
||||
29 main (int argc, char **argv) {
|
||||
30 GtkApplication *app;
|
||||
31 int stat;
|
||||
32
|
||||
33 app = gtk_application_new ("com.github.ToshioCP.da1", G_APPLICATION_FLAGS_NONE);
|
||||
34 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
35 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
36 g_object_unref (app);
|
||||
37 return stat;
|
||||
38 }
|
||||
39
|
||||
~~~
|
||||
|
||||
The function `main` is almost same as before.
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
CPPFLAGS="-I$HOME/local/include"
|
||||
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
|
||||
# linker
|
||||
LD_LIBRARY_PATH="$HOME/local/lib/x86_64-linux-gnu/"
|
||||
|
|
454
gfm/sec20.md
454
gfm/sec20.md
|
@ -34,87 +34,89 @@ The image in the previous subsection gives us the structure of the widgets.
|
|||
Title bar, four buttons in the tool bar and two widgets textview and drawing area.
|
||||
The ui file is as follows.
|
||||
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">color changer</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh1">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnr">
|
||||
19 <property name="label">Run</property>
|
||||
20 <signal name="clicked" handler="run_cb"></signal>
|
||||
21
|
||||
22 </object>
|
||||
23 </child>
|
||||
24 <child>
|
||||
25 <object class="GtkButton" id="btno">
|
||||
26 <property name="label">Open</property>
|
||||
27 <signal name="clicked" handler="open_cb"></signal>
|
||||
28 </object>
|
||||
29 </child>
|
||||
30 <child>
|
||||
31 <object class="GtkLabel" id="dmy2">
|
||||
32 <property name="hexpand">TRUE</property>
|
||||
33 </object>
|
||||
34 </child>
|
||||
35 <child>
|
||||
36 <object class="GtkButton" id="btns">
|
||||
37 <property name="label">Save</property>
|
||||
38 <signal name="clicked" handler="save_cb"></signal>
|
||||
39 </object>
|
||||
40 </child>
|
||||
41 <child>
|
||||
42 <object class="GtkButton" id="btnc">
|
||||
43 <property name="label">Close</property>
|
||||
44 <signal name="clicked" handler="close_cb"></signal>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 <child>
|
||||
48 <object class="GtkLabel" id="dmy3">
|
||||
49 <property name="width-chars">10</property>
|
||||
50 </object>
|
||||
51 </child>
|
||||
52 </object>
|
||||
53 </child>
|
||||
54 <child>
|
||||
55 <object class="GtkBox" id="boxh2">
|
||||
56 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
57 <property name="homogeneous">TRUE</property>
|
||||
58 <child>
|
||||
59 <object class="GtkScrolledWindow" id="scr">
|
||||
60 <property name="hexpand">TRUE</property>
|
||||
61 <property name="vexpand">TRUE</property>
|
||||
62 <child>
|
||||
63 <object class="TfeTextView" id="tv">
|
||||
64 <property name="wrap-mode">GTK_WRAP_WORD_CHAR</property>
|
||||
65 </object>
|
||||
66 </child>
|
||||
67 </object>
|
||||
68 </child>
|
||||
69 <child>
|
||||
70 <object class="GtkDrawingArea" id="da">
|
||||
71 <property name="hexpand">TRUE</property>
|
||||
72 <property name="vexpand">TRUE</property>
|
||||
73 </object>
|
||||
74 </child>
|
||||
75 </object>
|
||||
76 </child>
|
||||
77 </object>
|
||||
78 </child>
|
||||
79 </object>
|
||||
80 </interface>
|
||||
81
|
||||
~~~xml
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">color changer</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh1">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnr">
|
||||
19 <property name="label">Run</property>
|
||||
20 <signal name="clicked" handler="run_cb"></signal>
|
||||
21
|
||||
22 </object>
|
||||
23 </child>
|
||||
24 <child>
|
||||
25 <object class="GtkButton" id="btno">
|
||||
26 <property name="label">Open</property>
|
||||
27 <signal name="clicked" handler="open_cb"></signal>
|
||||
28 </object>
|
||||
29 </child>
|
||||
30 <child>
|
||||
31 <object class="GtkLabel" id="dmy2">
|
||||
32 <property name="hexpand">TRUE</property>
|
||||
33 </object>
|
||||
34 </child>
|
||||
35 <child>
|
||||
36 <object class="GtkButton" id="btns">
|
||||
37 <property name="label">Save</property>
|
||||
38 <signal name="clicked" handler="save_cb"></signal>
|
||||
39 </object>
|
||||
40 </child>
|
||||
41 <child>
|
||||
42 <object class="GtkButton" id="btnc">
|
||||
43 <property name="label">Close</property>
|
||||
44 <signal name="clicked" handler="close_cb"></signal>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 <child>
|
||||
48 <object class="GtkLabel" id="dmy3">
|
||||
49 <property name="width-chars">10</property>
|
||||
50 </object>
|
||||
51 </child>
|
||||
52 </object>
|
||||
53 </child>
|
||||
54 <child>
|
||||
55 <object class="GtkBox" id="boxh2">
|
||||
56 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
57 <property name="homogeneous">TRUE</property>
|
||||
58 <child>
|
||||
59 <object class="GtkScrolledWindow" id="scr">
|
||||
60 <property name="hexpand">TRUE</property>
|
||||
61 <property name="vexpand">TRUE</property>
|
||||
62 <child>
|
||||
63 <object class="TfeTextView" id="tv">
|
||||
64 <property name="wrap-mode">GTK_WRAP_WORD_CHAR</property>
|
||||
65 </object>
|
||||
66 </child>
|
||||
67 </object>
|
||||
68 </child>
|
||||
69 <child>
|
||||
70 <object class="GtkDrawingArea" id="da">
|
||||
71 <property name="hexpand">TRUE</property>
|
||||
72 <property name="vexpand">TRUE</property>
|
||||
73 </object>
|
||||
74 </child>
|
||||
75 </object>
|
||||
76 </child>
|
||||
77 </object>
|
||||
78 </child>
|
||||
79 </object>
|
||||
80 </interface>
|
||||
81
|
||||
~~~
|
||||
|
||||
- 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).
|
||||
|
@ -132,12 +134,14 @@ TfeTextView is a child of GtkScrolledWindow.
|
|||
The xml file for the resource compiler is almost same as before.
|
||||
Just substitute "color" for "tfe".
|
||||
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/color">
|
||||
4 <file>color.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/color">
|
||||
4 <file>color.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~
|
||||
|
||||
# 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.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #include "tfetextview.h"
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #include "tfetextview.h"
|
||||
~~~
|
||||
|
||||
# Colorapplication.c
|
||||
|
||||
|
@ -169,128 +175,130 @@ Particularly, `Run` signal handler is the point in this program.
|
|||
|
||||
The following is `colorapplication.c`.
|
||||
|
||||
1 #include "color.h"
|
||||
2
|
||||
3 static GtkWidget *win;
|
||||
4 static GtkWidget *tv;
|
||||
5 static GtkWidget *da;
|
||||
6
|
||||
7 static cairo_surface_t *surface = NULL;
|
||||
8
|
||||
9 static void
|
||||
10 run (void) {
|
||||
11 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
12 GtkTextIter start_iter;
|
||||
13 GtkTextIter end_iter;
|
||||
14 char *contents;
|
||||
15 cairo_t *cr;
|
||||
16
|
||||
17 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
18 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
19 if (surface) {
|
||||
20 cr = cairo_create (surface);
|
||||
21 if (g_strcmp0 ("red", contents) == 0)
|
||||
22 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
23 else if (g_strcmp0 ("green", contents) == 0)
|
||||
24 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
25 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
26 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
27 else if (g_strcmp0 ("white", contents) == 0)
|
||||
28 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
29 else if (g_strcmp0 ("black", contents) == 0)
|
||||
30 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
31 else if (g_strcmp0 ("light", contents) == 0)
|
||||
32 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
33 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
34 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
35 else
|
||||
36 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
37 cairo_paint (cr);
|
||||
38 cairo_destroy (cr);
|
||||
39 }
|
||||
40 }
|
||||
41
|
||||
42 void
|
||||
43 run_cb (GtkWidget *btnr) {
|
||||
44 run ();
|
||||
45 gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
46 }
|
||||
47
|
||||
48 void
|
||||
49 open_cb (GtkWidget *btno) {
|
||||
50 tfe_text_view_open (TFE_TEXT_VIEW (tv), win);
|
||||
51 }
|
||||
52
|
||||
53 void
|
||||
54 save_cb (GtkWidget *btns) {
|
||||
55 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
56 }
|
||||
57
|
||||
58 void
|
||||
59 close_cb (GtkWidget *btnc) {
|
||||
60 if (surface)
|
||||
61 cairo_surface_destroy (surface);
|
||||
62 gtk_window_destroy (GTK_WINDOW (win));
|
||||
63 }
|
||||
64
|
||||
65 static void
|
||||
66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
67 if (surface)
|
||||
68 cairo_surface_destroy (surface);
|
||||
69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
70 run ();
|
||||
71 }
|
||||
72
|
||||
73 static void
|
||||
74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
75 if (surface) {
|
||||
76 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
77 cairo_paint (cr);
|
||||
78 }
|
||||
79 }
|
||||
80
|
||||
81 static void
|
||||
82 activate (GApplication *application) {
|
||||
83 gtk_widget_show (win);
|
||||
84 }
|
||||
85
|
||||
86 static void
|
||||
87 startup (GApplication *application) {
|
||||
88 GtkApplication *app = GTK_APPLICATION (application);
|
||||
89 GtkBuilder *build;
|
||||
90
|
||||
91 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
92 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
93 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
94 tv = GTK_WIDGET (gtk_builder_get_object (build, "tv"));
|
||||
95 da = GTK_WIDGET (gtk_builder_get_object (build, "da"));
|
||||
96 g_object_unref(build);
|
||||
97 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
98 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
99
|
||||
100 GdkDisplay *display;
|
||||
101
|
||||
102 display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
103 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
104 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
105 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
106 }
|
||||
107
|
||||
108 int
|
||||
109 main (int argc, char **argv) {
|
||||
110 GtkApplication *app;
|
||||
111 int stat;
|
||||
112
|
||||
113 app = gtk_application_new ("com.github.ToshioCP.color", G_APPLICATION_FLAGS_NONE);
|
||||
114
|
||||
115 g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
|
||||
116 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
117
|
||||
118 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
119 g_object_unref (app);
|
||||
120 return stat;
|
||||
121 }
|
||||
122
|
||||
~~~C
|
||||
1 #include "color.h"
|
||||
2
|
||||
3 static GtkWidget *win;
|
||||
4 static GtkWidget *tv;
|
||||
5 static GtkWidget *da;
|
||||
6
|
||||
7 static cairo_surface_t *surface = NULL;
|
||||
8
|
||||
9 static void
|
||||
10 run (void) {
|
||||
11 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
12 GtkTextIter start_iter;
|
||||
13 GtkTextIter end_iter;
|
||||
14 char *contents;
|
||||
15 cairo_t *cr;
|
||||
16
|
||||
17 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
18 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
19 if (surface) {
|
||||
20 cr = cairo_create (surface);
|
||||
21 if (g_strcmp0 ("red", contents) == 0)
|
||||
22 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
23 else if (g_strcmp0 ("green", contents) == 0)
|
||||
24 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
25 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
26 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
27 else if (g_strcmp0 ("white", contents) == 0)
|
||||
28 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
29 else if (g_strcmp0 ("black", contents) == 0)
|
||||
30 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
31 else if (g_strcmp0 ("light", contents) == 0)
|
||||
32 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
33 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
34 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
35 else
|
||||
36 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
37 cairo_paint (cr);
|
||||
38 cairo_destroy (cr);
|
||||
39 }
|
||||
40 }
|
||||
41
|
||||
42 void
|
||||
43 run_cb (GtkWidget *btnr) {
|
||||
44 run ();
|
||||
45 gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
46 }
|
||||
47
|
||||
48 void
|
||||
49 open_cb (GtkWidget *btno) {
|
||||
50 tfe_text_view_open (TFE_TEXT_VIEW (tv), win);
|
||||
51 }
|
||||
52
|
||||
53 void
|
||||
54 save_cb (GtkWidget *btns) {
|
||||
55 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
56 }
|
||||
57
|
||||
58 void
|
||||
59 close_cb (GtkWidget *btnc) {
|
||||
60 if (surface)
|
||||
61 cairo_surface_destroy (surface);
|
||||
62 gtk_window_destroy (GTK_WINDOW (win));
|
||||
63 }
|
||||
64
|
||||
65 static void
|
||||
66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
67 if (surface)
|
||||
68 cairo_surface_destroy (surface);
|
||||
69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
70 run ();
|
||||
71 }
|
||||
72
|
||||
73 static void
|
||||
74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
75 if (surface) {
|
||||
76 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
77 cairo_paint (cr);
|
||||
78 }
|
||||
79 }
|
||||
80
|
||||
81 static void
|
||||
82 activate (GApplication *application) {
|
||||
83 gtk_widget_show (win);
|
||||
84 }
|
||||
85
|
||||
86 static void
|
||||
87 startup (GApplication *application) {
|
||||
88 GtkApplication *app = GTK_APPLICATION (application);
|
||||
89 GtkBuilder *build;
|
||||
90
|
||||
91 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
92 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
93 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
94 tv = GTK_WIDGET (gtk_builder_get_object (build, "tv"));
|
||||
95 da = GTK_WIDGET (gtk_builder_get_object (build, "da"));
|
||||
96 g_object_unref(build);
|
||||
97 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
98 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
99
|
||||
100 GdkDisplay *display;
|
||||
101
|
||||
102 display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
103 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
104 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
105 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
106 }
|
||||
107
|
||||
108 int
|
||||
109 main (int argc, char **argv) {
|
||||
110 GtkApplication *app;
|
||||
111 int stat;
|
||||
112
|
||||
113 app = gtk_application_new ("com.github.ToshioCP.color", G_APPLICATION_FLAGS_NONE);
|
||||
114
|
||||
115 g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
|
||||
116 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
117
|
||||
118 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
119 g_object_unref (app);
|
||||
120 return stat;
|
||||
121 }
|
||||
122
|
||||
~~~
|
||||
|
||||
- 108-121: The function `main` is almost same as before but there are some differences.
|
||||
The application ID is "com.github.ToshioCP.color".
|
||||
|
@ -332,16 +340,18 @@ Alpha channel is used.
|
|||
This file is almost same as before.
|
||||
An argument "export_dynamic: true" is added to executable function.
|
||||
|
||||
1 project('color', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','color.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('colorapplication.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
||||
~~~meson
|
||||
1 project('color', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','color.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('colorapplication.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
||||
~~~
|
||||
|
||||
# Compile and execute it
|
||||
|
||||
|
|
110
gfm/sec3.md
110
gfm/sec3.md
|
@ -20,19 +20,21 @@ That's all.
|
|||
Very simple.
|
||||
The following is the C code representing the scenario above.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 int
|
||||
4 main (int argc, char **argv) {
|
||||
5 GtkApplication *app;
|
||||
6 int stat;
|
||||
7
|
||||
8 app = gtk_application_new ("com.github.ToshioCP.pr1", G_APPLICATION_FLAGS_NONE);
|
||||
9 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
10 g_object_unref (app);
|
||||
11 return stat;
|
||||
12 }
|
||||
13
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 int
|
||||
4 main (int argc, char **argv) {
|
||||
5 GtkApplication *app;
|
||||
6 int stat;
|
||||
7
|
||||
8 app = gtk_application_new ("com.github.ToshioCP.pr1", G_APPLICATION_FLAGS_NONE);
|
||||
9 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
10 g_object_unref (app);
|
||||
11 return stat;
|
||||
12 }
|
||||
13
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
@ -54,7 +56,9 @@ Let's run it.
|
|||
|
||||
$ ./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.
|
||||
|
@ -97,25 +101,27 @@ Now we can solve the problem in `pr1.c`.
|
|||
We need to connect the activate signal to a handler.
|
||||
We use a function `g_signal_connect` which connects a signal to a handler.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer *user_data) {
|
||||
5 g_print ("GtkApplication is activated.\n");
|
||||
6 }
|
||||
7
|
||||
8 int
|
||||
9 main (int argc, char **argv) {
|
||||
10 GtkApplication *app;
|
||||
11 int stat;
|
||||
12
|
||||
13 app = gtk_application_new ("com.github.ToshioCP.pr2", G_APPLICATION_FLAGS_NONE);
|
||||
14 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
15 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
16 g_object_unref (app);
|
||||
17 return stat;
|
||||
18 }
|
||||
19
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer *user_data) {
|
||||
5 g_print ("GtkApplication is activated.\n");
|
||||
6 }
|
||||
7
|
||||
8 int
|
||||
9 main (int argc, char **argv) {
|
||||
10 GtkApplication *app;
|
||||
11 int stat;
|
||||
12
|
||||
13 app = gtk_application_new ("com.github.ToshioCP.pr2", G_APPLICATION_FLAGS_NONE);
|
||||
14 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
15 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
16 g_object_unref (app);
|
||||
17 return stat;
|
||||
18 }
|
||||
19
|
||||
~~~
|
||||
|
||||
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`.
|
||||
|
@ -185,14 +191,16 @@ Now rewrite the function `on_activate`.
|
|||
|
||||
#### Generate a GtkWindow
|
||||
|
||||
1 static void
|
||||
2 on_activate (GApplication *app, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4
|
||||
5 win = gtk_window_new ();
|
||||
6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
7 gtk_widget_show (win);
|
||||
8 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 on_activate (GApplication *app, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4
|
||||
5 win = gtk_window_new ();
|
||||
6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
7 gtk_widget_show (win);
|
||||
8 }
|
||||
~~~
|
||||
|
||||
Widget is an abstract concept that includes all the GUI interfaces such as windows, dialogs, buttons, multiline text, containers and so on.
|
||||
And GtkWidget is a base object from which all the GUI objects derive.
|
||||
|
@ -265,15 +273,17 @@ It is recommended to use it instead of GtkWindow when you use GtkApplication.
|
|||
|
||||
Now rewrite the program and use GtkAppliction Window.
|
||||
|
||||
1 static void
|
||||
2 on_activate (GApplication *app, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4
|
||||
5 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
6 gtk_window_set_title (GTK_WINDOW (win), "pr4");
|
||||
7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
8 gtk_widget_show (win);
|
||||
9 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 on_activate (GApplication *app, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4
|
||||
5 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
6 gtk_window_set_title (GTK_WINDOW (win), "pr4");
|
||||
7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
8 gtk_widget_show (win);
|
||||
9 }
|
||||
~~~
|
||||
|
||||
When you generate GtkApplicationWindow, you need to give GtkApplication object as an argument.
|
||||
Then it automatically connect these two objects.
|
||||
|
|
292
gfm/sec4.md
292
gfm/sec4.md
|
@ -11,35 +11,37 @@ Now we go on to the next topic, widgets in the window.
|
|||
The simplest widget is GtkLabel.
|
||||
It is a widget with a string in it.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 GtkWidget *win;
|
||||
6 GtkWidget *lab;
|
||||
7
|
||||
8 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
9 gtk_window_set_title (GTK_WINDOW (win), "lb1");
|
||||
10 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
11
|
||||
12 lab = gtk_label_new ("Hello.");
|
||||
13 gtk_window_set_child (GTK_WINDOW (win), lab);
|
||||
14
|
||||
15 gtk_widget_show (win);
|
||||
16 }
|
||||
17
|
||||
18 int
|
||||
19 main (int argc, char **argv) {
|
||||
20 GtkApplication *app;
|
||||
21 int stat;
|
||||
22
|
||||
23 app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_FLAGS_NONE);
|
||||
24 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
25 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
26 g_object_unref (app);
|
||||
27 return stat;
|
||||
28 }
|
||||
29
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 GtkWidget *win;
|
||||
6 GtkWidget *lab;
|
||||
7
|
||||
8 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
9 gtk_window_set_title (GTK_WINDOW (win), "lb1");
|
||||
10 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
11
|
||||
12 lab = gtk_label_new ("Hello.");
|
||||
13 gtk_window_set_child (GTK_WINDOW (win), lab);
|
||||
14
|
||||
15 gtk_widget_show (win);
|
||||
16 }
|
||||
17
|
||||
18 int
|
||||
19 main (int argc, char **argv) {
|
||||
20 GtkApplication *app;
|
||||
21 int stat;
|
||||
22
|
||||
23 app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_FLAGS_NONE);
|
||||
24 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
25 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
26 g_object_unref (app);
|
||||
27 return stat;
|
||||
28 }
|
||||
29
|
||||
~~~
|
||||
|
||||
Save this program to a file `lb1.c`.
|
||||
Then compile and run it.
|
||||
|
@ -100,41 +102,43 @@ In this subsection, we will make a button with a label.
|
|||
When a button is clicked on, it emits a "clicked" signal.
|
||||
The following program shows how to catch the signal and do something.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 click_cb (GtkButton *btn, gpointer user_data) {
|
||||
5 g_print ("Clicked.\n");
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 on_activate (GApplication *app, gpointer user_data) {
|
||||
10 GtkWidget *win;
|
||||
11 GtkWidget *btn;
|
||||
12
|
||||
13 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
14 gtk_window_set_title (GTK_WINDOW (win), "lb2");
|
||||
15 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
16
|
||||
17 btn = gtk_button_new_with_label ("Click me");
|
||||
18 gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
19 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
|
||||
20
|
||||
21 gtk_widget_show (win);
|
||||
22 }
|
||||
23
|
||||
24 int
|
||||
25 main (int argc, char **argv) {
|
||||
26 GtkApplication *app;
|
||||
27 int stat;
|
||||
28
|
||||
29 app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_FLAGS_NONE);
|
||||
30 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
31 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
32 g_object_unref (app);
|
||||
33 return stat;
|
||||
34 }
|
||||
35
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 click_cb (GtkButton *btn, gpointer user_data) {
|
||||
5 g_print ("Clicked.\n");
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 on_activate (GApplication *app, gpointer user_data) {
|
||||
10 GtkWidget *win;
|
||||
11 GtkWidget *btn;
|
||||
12
|
||||
13 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
14 gtk_window_set_title (GTK_WINDOW (win), "lb2");
|
||||
15 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
16
|
||||
17 btn = gtk_button_new_with_label ("Click me");
|
||||
18 gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
19 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
|
||||
20
|
||||
21 gtk_widget_show (win);
|
||||
22 }
|
||||
23
|
||||
24 int
|
||||
25 main (int argc, char **argv) {
|
||||
26 GtkApplication *app;
|
||||
27 int stat;
|
||||
28
|
||||
29 app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_FLAGS_NONE);
|
||||
30 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
31 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
32 g_object_unref (app);
|
||||
33 return stat;
|
||||
34 }
|
||||
35
|
||||
~~~
|
||||
|
||||
Look at the line 17 to 19.
|
||||
First, generate a GtkButton widget `btn` with a label "Click me".
|
||||
|
@ -157,27 +161,29 @@ However, using g_print is out of harmony with GTK which is a GUI library.
|
|||
So, we will change the handler.
|
||||
The following code is `lb3.c`.
|
||||
|
||||
1 static void
|
||||
2 click_cb (GtkButton *btn, gpointer user_data) {
|
||||
3 GtkWindow *win = GTK_WINDOW (user_data);
|
||||
4 gtk_window_destroy (win);
|
||||
5 }
|
||||
6
|
||||
7 static void
|
||||
8 on_activate (GApplication *app, gpointer user_data) {
|
||||
9 GtkWidget *win;
|
||||
10 GtkWidget *btn;
|
||||
11
|
||||
12 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
13 gtk_window_set_title (GTK_WINDOW (win), "lb3");
|
||||
14 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
15
|
||||
16 btn = gtk_button_new_with_label ("Quit");
|
||||
17 gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
18 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
|
||||
19
|
||||
20 gtk_widget_show (win);
|
||||
21 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 click_cb (GtkButton *btn, gpointer user_data) {
|
||||
3 GtkWindow *win = GTK_WINDOW (user_data);
|
||||
4 gtk_window_destroy (win);
|
||||
5 }
|
||||
6
|
||||
7 static void
|
||||
8 on_activate (GApplication *app, gpointer user_data) {
|
||||
9 GtkWidget *win;
|
||||
10 GtkWidget *btn;
|
||||
11
|
||||
12 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
13 gtk_window_set_title (GTK_WINDOW (win), "lb3");
|
||||
14 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
15
|
||||
16 btn = gtk_button_new_with_label ("Quit");
|
||||
17 gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
18 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
|
||||
19
|
||||
20 gtk_widget_show (win);
|
||||
21 }
|
||||
~~~
|
||||
|
||||
And the difference between `lb2.c` and `lb3.c` is as follows.
|
||||
|
||||
|
@ -237,63 +243,65 @@ After this, the Widgets are connected as following diagram.
|
|||
|
||||
Now, code it.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 click1_cb (GtkButton *btn, gpointer user_data) {
|
||||
5 const gchar *s;
|
||||
6
|
||||
7 s = gtk_button_get_label (btn);
|
||||
8 if (g_strcmp0 (s, "Hello.") == 0)
|
||||
9 gtk_button_set_label (btn, "Good-bye.");
|
||||
10 else
|
||||
11 gtk_button_set_label (btn, "Hello.");
|
||||
12 }
|
||||
13
|
||||
14 static void
|
||||
15 click2_cb (GtkButton *btn, gpointer user_data) {
|
||||
16 GtkWindow *win = GTK_WINDOW (user_data);
|
||||
17 gtk_window_destroy (win);
|
||||
18 }
|
||||
19
|
||||
20 static void
|
||||
21 on_activate (GApplication *app, gpointer user_data) {
|
||||
22 GtkWidget *win;
|
||||
23 GtkWidget *box;
|
||||
24 GtkWidget *btn1;
|
||||
25 GtkWidget *btn2;
|
||||
26
|
||||
27 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
28 gtk_window_set_title (GTK_WINDOW (win), "lb4");
|
||||
29 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
30
|
||||
31 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
32 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
|
||||
33 gtk_window_set_child (GTK_WINDOW (win), box);
|
||||
34
|
||||
35 btn1 = gtk_button_new_with_label ("Hello.");
|
||||
36 g_signal_connect (btn1, "clicked", G_CALLBACK (click1_cb), NULL);
|
||||
37
|
||||
38 btn2 = gtk_button_new_with_label ("Quit");
|
||||
39 g_signal_connect (btn2, "clicked", G_CALLBACK (click2_cb), win);
|
||||
40
|
||||
41 gtk_box_append (GTK_BOX (box), btn1);
|
||||
42 gtk_box_append (GTK_BOX (box), btn2);
|
||||
43
|
||||
44 gtk_widget_show (win);
|
||||
45 }
|
||||
46
|
||||
47 int
|
||||
48 main (int argc, char **argv) {
|
||||
49 GtkApplication *app;
|
||||
50 int stat;
|
||||
51
|
||||
52 app = gtk_application_new ("com.github.ToshioCP.lb4", G_APPLICATION_FLAGS_NONE);
|
||||
53 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
54 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
55 g_object_unref (app);
|
||||
56 return stat;
|
||||
57 }
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 click1_cb (GtkButton *btn, gpointer user_data) {
|
||||
5 const gchar *s;
|
||||
6
|
||||
7 s = gtk_button_get_label (btn);
|
||||
8 if (g_strcmp0 (s, "Hello.") == 0)
|
||||
9 gtk_button_set_label (btn, "Good-bye.");
|
||||
10 else
|
||||
11 gtk_button_set_label (btn, "Hello.");
|
||||
12 }
|
||||
13
|
||||
14 static void
|
||||
15 click2_cb (GtkButton *btn, gpointer user_data) {
|
||||
16 GtkWindow *win = GTK_WINDOW (user_data);
|
||||
17 gtk_window_destroy (win);
|
||||
18 }
|
||||
19
|
||||
20 static void
|
||||
21 on_activate (GApplication *app, gpointer user_data) {
|
||||
22 GtkWidget *win;
|
||||
23 GtkWidget *box;
|
||||
24 GtkWidget *btn1;
|
||||
25 GtkWidget *btn2;
|
||||
26
|
||||
27 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
28 gtk_window_set_title (GTK_WINDOW (win), "lb4");
|
||||
29 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
30
|
||||
31 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
32 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
|
||||
33 gtk_window_set_child (GTK_WINDOW (win), box);
|
||||
34
|
||||
35 btn1 = gtk_button_new_with_label ("Hello.");
|
||||
36 g_signal_connect (btn1, "clicked", G_CALLBACK (click1_cb), NULL);
|
||||
37
|
||||
38 btn2 = gtk_button_new_with_label ("Quit");
|
||||
39 g_signal_connect (btn2, "clicked", G_CALLBACK (click2_cb), win);
|
||||
40
|
||||
41 gtk_box_append (GTK_BOX (box), btn1);
|
||||
42 gtk_box_append (GTK_BOX (box), btn2);
|
||||
43
|
||||
44 gtk_widget_show (win);
|
||||
45 }
|
||||
46
|
||||
47 int
|
||||
48 main (int argc, char **argv) {
|
||||
49 GtkApplication *app;
|
||||
50 int stat;
|
||||
51
|
||||
52 app = gtk_application_new ("com.github.ToshioCP.lb4", G_APPLICATION_FLAGS_NONE);
|
||||
53 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
54 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
55 g_object_unref (app);
|
||||
56 return stat;
|
||||
57 }
|
||||
~~~
|
||||
|
||||
Look at the function `on_activate`.
|
||||
|
||||
|
|
196
gfm/sec5.md
196
gfm/sec5.md
|
@ -10,52 +10,54 @@ GtkTextview is a widget for multiline text editing.
|
|||
GtkTextBuffer is a text buffer which is connected to GtkTextView.
|
||||
See a sample program `tfv1.c` below.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 GtkWidget *win;
|
||||
6 GtkWidget *tv;
|
||||
7 GtkTextBuffer *tb;
|
||||
8 gchar *text;
|
||||
9
|
||||
10 text =
|
||||
11 "Once upon a time, there was an old man who was called Taketori-no-Okina."
|
||||
12 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
13 "One day, he went into a mountain and found a shining bamboo."
|
||||
14 "\"What a mysterious bamboo it is!,\" he said."
|
||||
15 "He cut it, then there was a small cute baby girl in it."
|
||||
16 "The girl was shining faintly."
|
||||
17 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
18 "His wife was surprized at his tale."
|
||||
19 "They were very happy because they had no children."
|
||||
20 ;
|
||||
21 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
22 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
23 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
24
|
||||
25 tv = gtk_text_view_new ();
|
||||
26 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
27 gtk_text_buffer_set_text (tb, text, -1);
|
||||
28 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
29
|
||||
30 gtk_window_set_child (GTK_WINDOW (win), tv);
|
||||
31
|
||||
32 gtk_widget_show (win);
|
||||
33 }
|
||||
34
|
||||
35 int
|
||||
36 main (int argc, char **argv) {
|
||||
37 GtkApplication *app;
|
||||
38 int stat;
|
||||
39
|
||||
40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||
41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
42 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
43 g_object_unref (app);
|
||||
44 return stat;
|
||||
45 }
|
||||
46
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 GtkWidget *win;
|
||||
6 GtkWidget *tv;
|
||||
7 GtkTextBuffer *tb;
|
||||
8 gchar *text;
|
||||
9
|
||||
10 text =
|
||||
11 "Once upon a time, there was an old man who was called Taketori-no-Okina."
|
||||
12 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
13 "One day, he went into a mountain and found a shining bamboo."
|
||||
14 "\"What a mysterious bamboo it is!,\" he said."
|
||||
15 "He cut it, then there was a small cute baby girl in it."
|
||||
16 "The girl was shining faintly."
|
||||
17 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
18 "His wife was surprized at his tale."
|
||||
19 "They were very happy because they had no children."
|
||||
20 ;
|
||||
21 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
22 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
23 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
24
|
||||
25 tv = gtk_text_view_new ();
|
||||
26 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
27 gtk_text_buffer_set_text (tb, text, -1);
|
||||
28 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
29
|
||||
30 gtk_window_set_child (GTK_WINDOW (win), tv);
|
||||
31
|
||||
32 gtk_widget_show (win);
|
||||
33 }
|
||||
34
|
||||
35 int
|
||||
36 main (int argc, char **argv) {
|
||||
37 GtkApplication *app;
|
||||
38 int stat;
|
||||
39
|
||||
40 app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||
41 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
42 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
43 g_object_unref (app);
|
||||
44 return stat;
|
||||
45 }
|
||||
46
|
||||
~~~
|
||||
|
||||
Look at line 25.
|
||||
GtkTextView is generated and its pointer is assigned to `tv`.
|
||||
|
@ -108,56 +110,58 @@ The difference between these two files is very little.
|
|||
|
||||
Though you can modify the source file by this diff output, It's good for you to show `tfv2.c`.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 GtkWidget *win;
|
||||
6 GtkWidget *scr;
|
||||
7 GtkWidget *tv;
|
||||
8 GtkTextBuffer *tb;
|
||||
9 gchar *text;
|
||||
10
|
||||
11 text =
|
||||
12 "Once upon a time, there was an old man who was called Taketori-no-Okina."
|
||||
13 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
14 "One day, he went into a mountain and found a shining bamboo."
|
||||
15 "\"What a mysterious bamboo it is!,\" he said."
|
||||
16 "He cut it, then there was a small cute baby girl in it."
|
||||
17 "The girl was shining faintly."
|
||||
18 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
19 "His wife was surprized at his tale."
|
||||
20 "They were very happy because they had no children."
|
||||
21 ;
|
||||
22 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
23 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
25
|
||||
26 scr = gtk_scrolled_window_new ();
|
||||
27 gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
28
|
||||
29 tv = gtk_text_view_new ();
|
||||
30 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
31 gtk_text_buffer_set_text (tb, text, -1);
|
||||
32 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
33
|
||||
34 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
35
|
||||
36 gtk_widget_show (win);
|
||||
37 }
|
||||
38
|
||||
39 int
|
||||
40 main (int argc, char **argv) {
|
||||
41 GtkApplication *app;
|
||||
42 int stat;
|
||||
43
|
||||
44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||
45 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
46 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
47 g_object_unref (app);
|
||||
48 return stat;
|
||||
49 }
|
||||
50
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 GtkWidget *win;
|
||||
6 GtkWidget *scr;
|
||||
7 GtkWidget *tv;
|
||||
8 GtkTextBuffer *tb;
|
||||
9 gchar *text;
|
||||
10
|
||||
11 text =
|
||||
12 "Once upon a time, there was an old man who was called Taketori-no-Okina."
|
||||
13 "It is a japanese word that means a man whose work is making bamboo baskets.\n"
|
||||
14 "One day, he went into a mountain and found a shining bamboo."
|
||||
15 "\"What a mysterious bamboo it is!,\" he said."
|
||||
16 "He cut it, then there was a small cute baby girl in it."
|
||||
17 "The girl was shining faintly."
|
||||
18 "He thought this baby girl is a gift from Heaven and took her home.\n"
|
||||
19 "His wife was surprized at his tale."
|
||||
20 "They were very happy because they had no children."
|
||||
21 ;
|
||||
22 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
23 gtk_window_set_title (GTK_WINDOW (win), "Taketori");
|
||||
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
25
|
||||
26 scr = gtk_scrolled_window_new ();
|
||||
27 gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
28
|
||||
29 tv = gtk_text_view_new ();
|
||||
30 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
31 gtk_text_buffer_set_text (tb, text, -1);
|
||||
32 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
33
|
||||
34 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
35
|
||||
36 gtk_widget_show (win);
|
||||
37 }
|
||||
38
|
||||
39 int
|
||||
40 main (int argc, char **argv) {
|
||||
41 GtkApplication *app;
|
||||
42 int stat;
|
||||
43
|
||||
44 app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||
45 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
46 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
47 g_object_unref (app);
|
||||
48 return stat;
|
||||
49 }
|
||||
50
|
||||
~~~
|
||||
|
||||
Now compile and run it.
|
||||
This time the window doesn't extend even if you type a lot of characters.
|
||||
|
|
258
gfm/sec6.md
258
gfm/sec6.md
|
@ -89,62 +89,64 @@ It works as follows.
|
|||
|
||||
The program is as follows.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 g_print ("You need a filename argument.\n");
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
10 GtkWidget *win;
|
||||
11 GtkWidget *scr;
|
||||
12 GtkWidget *tv;
|
||||
13 GtkTextBuffer *tb;
|
||||
14 char *contents;
|
||||
15 gsize length;
|
||||
16 char *filename;
|
||||
17
|
||||
18 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
19 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
20
|
||||
21 scr = gtk_scrolled_window_new ();
|
||||
22 gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
23
|
||||
24 tv = gtk_text_view_new ();
|
||||
25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
27 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
|
||||
28 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
29
|
||||
30 if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
||||
31 gtk_text_buffer_set_text (tb, contents, length);
|
||||
32 g_free (contents);
|
||||
33 filename = g_file_get_basename (files[0]);
|
||||
34 gtk_window_set_title (GTK_WINDOW (win), filename);
|
||||
35 g_free (filename);
|
||||
36 gtk_widget_show (win);
|
||||
37 } else {
|
||||
38 filename = g_file_get_path (files[0]);
|
||||
39 g_print ("No such file: %s.\n", filename);
|
||||
40 gtk_window_destroy (GTK_WINDOW (win));
|
||||
41 }
|
||||
42 }
|
||||
43
|
||||
44 int
|
||||
45 main (int argc, char **argv) {
|
||||
46 GtkApplication *app;
|
||||
47 int stat;
|
||||
48
|
||||
49 app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||
50 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
51 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
52 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
53 g_object_unref (app);
|
||||
54 return stat;
|
||||
55 }
|
||||
56
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 g_print ("You need a filename argument.\n");
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
10 GtkWidget *win;
|
||||
11 GtkWidget *scr;
|
||||
12 GtkWidget *tv;
|
||||
13 GtkTextBuffer *tb;
|
||||
14 char *contents;
|
||||
15 gsize length;
|
||||
16 char *filename;
|
||||
17
|
||||
18 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
19 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
20
|
||||
21 scr = gtk_scrolled_window_new ();
|
||||
22 gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
23
|
||||
24 tv = gtk_text_view_new ();
|
||||
25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
27 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
|
||||
28 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
29
|
||||
30 if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
|
||||
31 gtk_text_buffer_set_text (tb, contents, length);
|
||||
32 g_free (contents);
|
||||
33 filename = g_file_get_basename (files[0]);
|
||||
34 gtk_window_set_title (GTK_WINDOW (win), filename);
|
||||
35 g_free (filename);
|
||||
36 gtk_widget_show (win);
|
||||
37 } else {
|
||||
38 filename = g_file_get_path (files[0]);
|
||||
39 g_print ("No such file: %s.\n", filename);
|
||||
40 gtk_window_destroy (GTK_WINDOW (win));
|
||||
41 }
|
||||
42 }
|
||||
43
|
||||
44 int
|
||||
45 main (int argc, char **argv) {
|
||||
46 GtkApplication *app;
|
||||
47 int stat;
|
||||
48
|
||||
49 app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
|
||||
50 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
51 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
52 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
53 g_object_unref (app);
|
||||
54 return stat;
|
||||
55 }
|
||||
56
|
||||
~~~
|
||||
|
||||
Save it as `tfv3.c`.
|
||||
Then compile and run it.
|
||||
|
@ -211,77 +213,79 @@ It is shown in the right screenshot.
|
|||
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
|
||||
Now I want to show you the program `tfv4.c`.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 g_print ("You need a filename argument.\n");
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
10 GtkWidget *win;
|
||||
11 GtkWidget *nb;
|
||||
12 GtkWidget *lab;
|
||||
13 GtkNotebookPage *nbp;
|
||||
14 GtkWidget *scr;
|
||||
15 GtkWidget *tv;
|
||||
16 GtkTextBuffer *tb;
|
||||
17 char *contents;
|
||||
18 gsize length;
|
||||
19 char *filename;
|
||||
20 int i;
|
||||
21
|
||||
22 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
23 gtk_window_set_title (GTK_WINDOW (win), "file viewer");
|
||||
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
25 gtk_window_maximize (GTK_WINDOW (win));
|
||||
26
|
||||
27 nb = gtk_notebook_new ();
|
||||
28 gtk_window_set_child (GTK_WINDOW (win), nb);
|
||||
29
|
||||
30 for (i = 0; i < n_files; i++) {
|
||||
31 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
32 scr = gtk_scrolled_window_new ();
|
||||
33 tv = gtk_text_view_new ();
|
||||
34 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
35 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
36 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
|
||||
37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
38
|
||||
39 gtk_text_buffer_set_text (tb, contents, length);
|
||||
40 g_free (contents);
|
||||
41 filename = g_file_get_basename (files[i]);
|
||||
42 lab = gtk_label_new (filename);
|
||||
43 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
44 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
45 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
46 g_free (filename);
|
||||
47 } else {
|
||||
48 filename = g_file_get_path (files[i]);
|
||||
49 g_print ("No such file: %s.\n", filename);
|
||||
50 g_free (filename);
|
||||
51 }
|
||||
52 }
|
||||
53 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0)
|
||||
54 gtk_widget_show (win);
|
||||
55 else
|
||||
56 gtk_window_destroy (GTK_WINDOW (win));
|
||||
57 }
|
||||
58
|
||||
59 int
|
||||
60 main (int argc, char **argv) {
|
||||
61 GtkApplication *app;
|
||||
62 int stat;
|
||||
63
|
||||
64 app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
|
||||
65 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
66 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
67 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
68 g_object_unref (app);
|
||||
69 return stat;
|
||||
70 }
|
||||
71
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 on_activate (GApplication *app, gpointer user_data) {
|
||||
5 g_print ("You need a filename argument.\n");
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
10 GtkWidget *win;
|
||||
11 GtkWidget *nb;
|
||||
12 GtkWidget *lab;
|
||||
13 GtkNotebookPage *nbp;
|
||||
14 GtkWidget *scr;
|
||||
15 GtkWidget *tv;
|
||||
16 GtkTextBuffer *tb;
|
||||
17 char *contents;
|
||||
18 gsize length;
|
||||
19 char *filename;
|
||||
20 int i;
|
||||
21
|
||||
22 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
23 gtk_window_set_title (GTK_WINDOW (win), "file viewer");
|
||||
24 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
25 gtk_window_maximize (GTK_WINDOW (win));
|
||||
26
|
||||
27 nb = gtk_notebook_new ();
|
||||
28 gtk_window_set_child (GTK_WINDOW (win), nb);
|
||||
29
|
||||
30 for (i = 0; i < n_files; i++) {
|
||||
31 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
32 scr = gtk_scrolled_window_new ();
|
||||
33 tv = gtk_text_view_new ();
|
||||
34 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
35 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
36 gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
|
||||
37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
38
|
||||
39 gtk_text_buffer_set_text (tb, contents, length);
|
||||
40 g_free (contents);
|
||||
41 filename = g_file_get_basename (files[i]);
|
||||
42 lab = gtk_label_new (filename);
|
||||
43 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
44 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
45 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
46 g_free (filename);
|
||||
47 } else {
|
||||
48 filename = g_file_get_path (files[i]);
|
||||
49 g_print ("No such file: %s.\n", filename);
|
||||
50 g_free (filename);
|
||||
51 }
|
||||
52 }
|
||||
53 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0)
|
||||
54 gtk_widget_show (win);
|
||||
55 else
|
||||
56 gtk_window_destroy (GTK_WINDOW (win));
|
||||
57 }
|
||||
58
|
||||
59 int
|
||||
60 main (int argc, char **argv) {
|
||||
61 GtkApplication *app;
|
||||
62 int stat;
|
||||
63
|
||||
64 app = gtk_application_new ("com.github.ToshioCP.tfv4", G_APPLICATION_HANDLES_OPEN);
|
||||
65 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
66 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
67 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
68 g_object_unref (app);
|
||||
69 return stat;
|
||||
70 }
|
||||
71
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
|
380
gfm/sec7.md
380
gfm/sec7.md
|
@ -57,39 +57,41 @@ So, I will just show you the way how to write the code and avoid the theoretical
|
|||
Let's define TfeTextView object which is a child object of GtkTextView.
|
||||
First, look at the program below.
|
||||
|
||||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
~~~C
|
||||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
|
||||
struct _TfeTextView
|
||||
{
|
||||
GtkTextView parent;
|
||||
GFile *file;
|
||||
};
|
||||
struct _TfeTextView
|
||||
{
|
||||
GtkTextView parent;
|
||||
GFile *file;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
|
||||
static void
|
||||
tfe_text_view_init (TfeTextView *tv) {
|
||||
}
|
||||
static void
|
||||
tfe_text_view_init (TfeTextView *tv) {
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
}
|
||||
static void
|
||||
tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
}
|
||||
|
||||
void
|
||||
tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
tv -> file = f;
|
||||
}
|
||||
void
|
||||
tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
tv -> file = f;
|
||||
}
|
||||
|
||||
GFile *
|
||||
tfe_text_view_get_file (TfeTextView *tv) {
|
||||
return tv -> file;
|
||||
}
|
||||
GFile *
|
||||
tfe_text_view_get_file (TfeTextView *tv) {
|
||||
return tv -> file;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
tfe_text_view_new (void) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
}
|
||||
GtkWidget *
|
||||
tfe_text_view_new (void) {
|
||||
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.
|
||||
Because to know the theory is very important for you to program GTK applications.
|
||||
|
@ -157,31 +159,33 @@ The argument win is GtkApplicationWindow, in which the signal "close-request" is
|
|||
`G_CALLBACK` cast is necessary for the handler.
|
||||
The program of before\_close is as follows.
|
||||
|
||||
1 static gboolean
|
||||
2 before_close (GtkWindow *win, GtkWidget *nb) {
|
||||
3 GtkWidget *scr;
|
||||
4 GtkWidget *tv;
|
||||
5 GFile *file;
|
||||
6 GtkTextBuffer *tb;
|
||||
7 GtkTextIter start_iter;
|
||||
8 GtkTextIter end_iter;
|
||||
9 char *contents;
|
||||
10 unsigned int n;
|
||||
11 unsigned int i;
|
||||
12
|
||||
13 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
||||
14 for (i = 0; i < n; ++i) {
|
||||
15 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
||||
16 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||
17 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
||||
18 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
19 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
20 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
21 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
|
||||
22 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
|
||||
23 }
|
||||
24 return FALSE;
|
||||
25 }
|
||||
~~~C
|
||||
1 static gboolean
|
||||
2 before_close (GtkWindow *win, GtkWidget *nb) {
|
||||
3 GtkWidget *scr;
|
||||
4 GtkWidget *tv;
|
||||
5 GFile *file;
|
||||
6 GtkTextBuffer *tb;
|
||||
7 GtkTextIter start_iter;
|
||||
8 GtkTextIter end_iter;
|
||||
9 char *contents;
|
||||
10 unsigned int n;
|
||||
11 unsigned int i;
|
||||
12
|
||||
13 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
||||
14 for (i = 0; i < n; ++i) {
|
||||
15 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
||||
16 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||
17 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
||||
18 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
19 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
20 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
21 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
|
||||
22 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
|
||||
23 }
|
||||
24 return FALSE;
|
||||
25 }
|
||||
~~~
|
||||
|
||||
The numbers on the left of items are line numbers in the source code.
|
||||
|
||||
|
@ -195,142 +199,144 @@ The numbers on the left of items are line numbers in the source code.
|
|||
|
||||
Now I will show you all the source code of `tfe1`.c.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 /* Define TfeTextView Widget which is the child object of GtkTextView */
|
||||
4
|
||||
5 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
6 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
7
|
||||
8 struct _TfeTextView
|
||||
9 {
|
||||
10 GtkTextView parent;
|
||||
11 GFile *file;
|
||||
12 };
|
||||
13
|
||||
14 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
15
|
||||
16 static void
|
||||
17 tfe_text_view_init (TfeTextView *tv) {
|
||||
18 }
|
||||
19
|
||||
20 static void
|
||||
21 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
22 }
|
||||
23
|
||||
24 void
|
||||
25 tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
26 tv -> file = f;
|
||||
27 }
|
||||
28
|
||||
29 GFile *
|
||||
30 tfe_text_view_get_file (TfeTextView *tv) {
|
||||
31 return tv -> file;
|
||||
32 }
|
||||
33
|
||||
34 GtkWidget *
|
||||
35 tfe_text_view_new (void) {
|
||||
36 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
37 }
|
||||
38
|
||||
39 /* ---------- end of the definition of TfeTextView ---------- */
|
||||
40
|
||||
41 static gboolean
|
||||
42 before_close (GtkWindow *win, GtkWidget *nb) {
|
||||
43 GtkWidget *scr;
|
||||
44 GtkWidget *tv;
|
||||
45 GFile *file;
|
||||
46 GtkTextBuffer *tb;
|
||||
47 GtkTextIter start_iter;
|
||||
48 GtkTextIter end_iter;
|
||||
49 char *contents;
|
||||
50 unsigned int n;
|
||||
51 unsigned int i;
|
||||
52
|
||||
53 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
||||
54 for (i = 0; i < n; ++i) {
|
||||
55 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
||||
56 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||
57 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
||||
58 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
59 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
60 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
61 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
|
||||
62 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
|
||||
63 }
|
||||
64 return FALSE;
|
||||
65 }
|
||||
66
|
||||
67 static void
|
||||
68 on_activate (GApplication *app, gpointer user_data) {
|
||||
69 g_print ("You need a filename argument.\n");
|
||||
70 }
|
||||
71
|
||||
72 static void
|
||||
73 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
74 GtkWidget *win;
|
||||
75 GtkWidget *nb;
|
||||
76 GtkWidget *lab;
|
||||
77 GtkNotebookPage *nbp;
|
||||
78 GtkWidget *scr;
|
||||
79 GtkWidget *tv;
|
||||
80 GtkTextBuffer *tb;
|
||||
81 char *contents;
|
||||
82 gsize length;
|
||||
83 char *filename;
|
||||
84 int i;
|
||||
85
|
||||
86 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
87 gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||
88 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
89 gtk_window_maximize (GTK_WINDOW (win));
|
||||
90
|
||||
91 nb = gtk_notebook_new ();
|
||||
92 gtk_window_set_child (GTK_WINDOW (win), nb);
|
||||
93
|
||||
94 for (i = 0; i < n_files; i++) {
|
||||
95 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
96 scr = gtk_scrolled_window_new ();
|
||||
97 tv = tfe_text_view_new ();
|
||||
98 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
99 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
100 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
101
|
||||
102 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
103 gtk_text_buffer_set_text (tb, contents, length);
|
||||
104 g_free (contents);
|
||||
105 filename = g_file_get_basename (files[i]);
|
||||
106 lab = gtk_label_new (filename);
|
||||
107 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
108 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
109 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
110 g_free (filename);
|
||||
111 } else {
|
||||
112 filename = g_file_get_path (files[i]);
|
||||
113 g_print ("No such file: %s.\n", filename);
|
||||
114 g_free (filename);
|
||||
115 }
|
||||
116 }
|
||||
117 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
118 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
||||
119 gtk_widget_show (win);
|
||||
120 } else
|
||||
121 gtk_window_destroy (GTK_WINDOW (win));
|
||||
122 }
|
||||
123
|
||||
124 int
|
||||
125 main (int argc, char **argv) {
|
||||
126 GtkApplication *app;
|
||||
127 int stat;
|
||||
128
|
||||
129 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
|
||||
130 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
131 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
132 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
133 g_object_unref (app);
|
||||
134 return stat;
|
||||
135 }
|
||||
136
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 /* Define TfeTextView Widget which is the child object of GtkTextView */
|
||||
4
|
||||
5 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
6 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
7
|
||||
8 struct _TfeTextView
|
||||
9 {
|
||||
10 GtkTextView parent;
|
||||
11 GFile *file;
|
||||
12 };
|
||||
13
|
||||
14 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
15
|
||||
16 static void
|
||||
17 tfe_text_view_init (TfeTextView *tv) {
|
||||
18 }
|
||||
19
|
||||
20 static void
|
||||
21 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
22 }
|
||||
23
|
||||
24 void
|
||||
25 tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
26 tv -> file = f;
|
||||
27 }
|
||||
28
|
||||
29 GFile *
|
||||
30 tfe_text_view_get_file (TfeTextView *tv) {
|
||||
31 return tv -> file;
|
||||
32 }
|
||||
33
|
||||
34 GtkWidget *
|
||||
35 tfe_text_view_new (void) {
|
||||
36 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
37 }
|
||||
38
|
||||
39 /* ---------- end of the definition of TfeTextView ---------- */
|
||||
40
|
||||
41 static gboolean
|
||||
42 before_close (GtkWindow *win, GtkWidget *nb) {
|
||||
43 GtkWidget *scr;
|
||||
44 GtkWidget *tv;
|
||||
45 GFile *file;
|
||||
46 GtkTextBuffer *tb;
|
||||
47 GtkTextIter start_iter;
|
||||
48 GtkTextIter end_iter;
|
||||
49 char *contents;
|
||||
50 unsigned int n;
|
||||
51 unsigned int i;
|
||||
52
|
||||
53 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
|
||||
54 for (i = 0; i < n; ++i) {
|
||||
55 scr = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), i);
|
||||
56 tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
|
||||
57 file = tfe_text_view_get_file (TFE_TEXT_VIEW (tv));
|
||||
58 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
59 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
60 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
61 if (! g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, NULL))
|
||||
62 g_print ("ERROR : Can't save %s.", g_file_get_path (file));
|
||||
63 }
|
||||
64 return FALSE;
|
||||
65 }
|
||||
66
|
||||
67 static void
|
||||
68 on_activate (GApplication *app, gpointer user_data) {
|
||||
69 g_print ("You need a filename argument.\n");
|
||||
70 }
|
||||
71
|
||||
72 static void
|
||||
73 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
74 GtkWidget *win;
|
||||
75 GtkWidget *nb;
|
||||
76 GtkWidget *lab;
|
||||
77 GtkNotebookPage *nbp;
|
||||
78 GtkWidget *scr;
|
||||
79 GtkWidget *tv;
|
||||
80 GtkTextBuffer *tb;
|
||||
81 char *contents;
|
||||
82 gsize length;
|
||||
83 char *filename;
|
||||
84 int i;
|
||||
85
|
||||
86 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
87 gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||
88 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
89 gtk_window_maximize (GTK_WINDOW (win));
|
||||
90
|
||||
91 nb = gtk_notebook_new ();
|
||||
92 gtk_window_set_child (GTK_WINDOW (win), nb);
|
||||
93
|
||||
94 for (i = 0; i < n_files; i++) {
|
||||
95 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
96 scr = gtk_scrolled_window_new ();
|
||||
97 tv = tfe_text_view_new ();
|
||||
98 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
99 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
100 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
101
|
||||
102 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
103 gtk_text_buffer_set_text (tb, contents, length);
|
||||
104 g_free (contents);
|
||||
105 filename = g_file_get_basename (files[i]);
|
||||
106 lab = gtk_label_new (filename);
|
||||
107 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
108 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
109 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
110 g_free (filename);
|
||||
111 } else {
|
||||
112 filename = g_file_get_path (files[i]);
|
||||
113 g_print ("No such file: %s.\n", filename);
|
||||
114 g_free (filename);
|
||||
115 }
|
||||
116 }
|
||||
117 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
118 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
||||
119 gtk_widget_show (win);
|
||||
120 } else
|
||||
121 gtk_window_destroy (GTK_WINDOW (win));
|
||||
122 }
|
||||
123
|
||||
124 int
|
||||
125 main (int argc, char **argv) {
|
||||
126 GtkApplication *app;
|
||||
127 int stat;
|
||||
128
|
||||
129 app = gtk_application_new ("com.github.ToshioCP.tfe1", G_APPLICATION_HANDLES_OPEN);
|
||||
130 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
131 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
132 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
133 g_object_unref (app);
|
||||
134 return stat;
|
||||
135 }
|
||||
136
|
||||
~~~
|
||||
|
||||
- 102: set the pointer to GFile into TfeTextView.
|
||||
`files[i]` is a pointer to GFile structure.
|
||||
|
|
464
gfm/sec8.md
464
gfm/sec8.md
|
@ -1,6 +1,6 @@
|
|||
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
|
||||
|
||||
|
@ -16,92 +16,94 @@ Signals and handlers will be explained later.
|
|||
The screenshot above shows the layout.
|
||||
The function `on_open` in the source code `tfe2.c` is as follows.
|
||||
|
||||
1 static void
|
||||
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4 GtkWidget *nb;
|
||||
5 GtkWidget *lab;
|
||||
6 GtkNotebookPage *nbp;
|
||||
7 GtkWidget *scr;
|
||||
8 GtkWidget *tv;
|
||||
9 GtkTextBuffer *tb;
|
||||
10 char *contents;
|
||||
11 gsize length;
|
||||
12 char *filename;
|
||||
13 int i;
|
||||
14
|
||||
15 GtkWidget *boxv;
|
||||
16 GtkWidget *boxh;
|
||||
17 GtkWidget *dmy1;
|
||||
18 GtkWidget *dmy2;
|
||||
19 GtkWidget *dmy3;
|
||||
20 GtkWidget *btnn; /* button for new */
|
||||
21 GtkWidget *btno; /* button for open */
|
||||
22 GtkWidget *btns; /* button for save */
|
||||
23 GtkWidget *btnc; /* button for close */
|
||||
24
|
||||
25 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
26 gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||
27 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||
28
|
||||
29 boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
30 gtk_window_set_child (GTK_WINDOW (win), boxv);
|
||||
31
|
||||
32 boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
33 gtk_box_append (GTK_BOX (boxv), boxh);
|
||||
34
|
||||
35 dmy1 = gtk_label_new(NULL); /* dummy label for left space */
|
||||
36 gtk_label_set_width_chars (GTK_LABEL (dmy1), 10);
|
||||
37 dmy2 = gtk_label_new(NULL); /* dummy label for center space */
|
||||
38 gtk_widget_set_hexpand (dmy2, TRUE);
|
||||
39 dmy3 = gtk_label_new(NULL); /* dummy label for right space */
|
||||
40 gtk_label_set_width_chars (GTK_LABEL (dmy3), 10);
|
||||
41 btnn = gtk_button_new_with_label ("New");
|
||||
42 btno = gtk_button_new_with_label ("Open");
|
||||
43 btns = gtk_button_new_with_label ("Save");
|
||||
44 btnc = gtk_button_new_with_label ("Close");
|
||||
45
|
||||
46 gtk_box_append (GTK_BOX (boxh), dmy1);
|
||||
47 gtk_box_append (GTK_BOX (boxh), btnn);
|
||||
48 gtk_box_append (GTK_BOX (boxh), btno);
|
||||
49 gtk_box_append (GTK_BOX (boxh), dmy2);
|
||||
50 gtk_box_append (GTK_BOX (boxh), btns);
|
||||
51 gtk_box_append (GTK_BOX (boxh), btnc);
|
||||
52 gtk_box_append (GTK_BOX (boxh), dmy3);
|
||||
53
|
||||
54 nb = gtk_notebook_new ();
|
||||
55 gtk_widget_set_hexpand (nb, TRUE);
|
||||
56 gtk_widget_set_vexpand (nb, TRUE);
|
||||
57 gtk_box_append (GTK_BOX (boxv), nb);
|
||||
58
|
||||
59 for (i = 0; i < n_files; i++) {
|
||||
60 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
61 scr = gtk_scrolled_window_new ();
|
||||
62 tv = tfe_text_view_new ();
|
||||
63 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
64 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
65 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
66
|
||||
67 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
68 gtk_text_buffer_set_text (tb, contents, length);
|
||||
69 g_free (contents);
|
||||
70 filename = g_file_get_basename (files[i]);
|
||||
71 lab = gtk_label_new (filename);
|
||||
72 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
73 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
74 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
75 g_free (filename);
|
||||
76 } else {
|
||||
77 filename = g_file_get_path (files[i]);
|
||||
78 g_print ("No such file: %s.\n", filename);
|
||||
79 g_free (filename);
|
||||
80 }
|
||||
81 }
|
||||
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
83 gtk_widget_show (win);
|
||||
84 } else
|
||||
85 gtk_window_destroy (GTK_WINDOW (win));
|
||||
86 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4 GtkWidget *nb;
|
||||
5 GtkWidget *lab;
|
||||
6 GtkNotebookPage *nbp;
|
||||
7 GtkWidget *scr;
|
||||
8 GtkWidget *tv;
|
||||
9 GtkTextBuffer *tb;
|
||||
10 char *contents;
|
||||
11 gsize length;
|
||||
12 char *filename;
|
||||
13 int i;
|
||||
14
|
||||
15 GtkWidget *boxv;
|
||||
16 GtkWidget *boxh;
|
||||
17 GtkWidget *dmy1;
|
||||
18 GtkWidget *dmy2;
|
||||
19 GtkWidget *dmy3;
|
||||
20 GtkWidget *btnn; /* button for new */
|
||||
21 GtkWidget *btno; /* button for open */
|
||||
22 GtkWidget *btns; /* button for save */
|
||||
23 GtkWidget *btnc; /* button for close */
|
||||
24
|
||||
25 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
26 gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||
27 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||
28
|
||||
29 boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
30 gtk_window_set_child (GTK_WINDOW (win), boxv);
|
||||
31
|
||||
32 boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
33 gtk_box_append (GTK_BOX (boxv), boxh);
|
||||
34
|
||||
35 dmy1 = gtk_label_new(NULL); /* dummy label for left space */
|
||||
36 gtk_label_set_width_chars (GTK_LABEL (dmy1), 10);
|
||||
37 dmy2 = gtk_label_new(NULL); /* dummy label for center space */
|
||||
38 gtk_widget_set_hexpand (dmy2, TRUE);
|
||||
39 dmy3 = gtk_label_new(NULL); /* dummy label for right space */
|
||||
40 gtk_label_set_width_chars (GTK_LABEL (dmy3), 10);
|
||||
41 btnn = gtk_button_new_with_label ("New");
|
||||
42 btno = gtk_button_new_with_label ("Open");
|
||||
43 btns = gtk_button_new_with_label ("Save");
|
||||
44 btnc = gtk_button_new_with_label ("Close");
|
||||
45
|
||||
46 gtk_box_append (GTK_BOX (boxh), dmy1);
|
||||
47 gtk_box_append (GTK_BOX (boxh), btnn);
|
||||
48 gtk_box_append (GTK_BOX (boxh), btno);
|
||||
49 gtk_box_append (GTK_BOX (boxh), dmy2);
|
||||
50 gtk_box_append (GTK_BOX (boxh), btns);
|
||||
51 gtk_box_append (GTK_BOX (boxh), btnc);
|
||||
52 gtk_box_append (GTK_BOX (boxh), dmy3);
|
||||
53
|
||||
54 nb = gtk_notebook_new ();
|
||||
55 gtk_widget_set_hexpand (nb, TRUE);
|
||||
56 gtk_widget_set_vexpand (nb, TRUE);
|
||||
57 gtk_box_append (GTK_BOX (boxv), nb);
|
||||
58
|
||||
59 for (i = 0; i < n_files; i++) {
|
||||
60 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
61 scr = gtk_scrolled_window_new ();
|
||||
62 tv = tfe_text_view_new ();
|
||||
63 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
64 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
65 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
66
|
||||
67 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
68 gtk_text_buffer_set_text (tb, contents, length);
|
||||
69 g_free (contents);
|
||||
70 filename = g_file_get_basename (files[i]);
|
||||
71 lab = gtk_label_new (filename);
|
||||
72 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
73 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
74 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
75 g_free (filename);
|
||||
76 } else {
|
||||
77 filename = g_file_get_path (files[i]);
|
||||
78 g_print ("No such file: %s.\n", filename);
|
||||
79 g_free (filename);
|
||||
80 }
|
||||
81 }
|
||||
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
83 gtk_widget_show (win);
|
||||
84 } else
|
||||
85 gtk_window_destroy (GTK_WINDOW (win));
|
||||
86 }
|
||||
~~~
|
||||
|
||||
The point is how to build the window.
|
||||
|
||||
|
@ -135,65 +137,67 @@ It reduces the cumbersom work.
|
|||
|
||||
First, let's look at the ui file `tfe3.ui` that defines a structure of the widgets.
|
||||
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">file editor</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnn">
|
||||
19 <property name="label">New</property>
|
||||
20 </object>
|
||||
21 </child>
|
||||
22 <child>
|
||||
23 <object class="GtkButton" id="btno">
|
||||
24 <property name="label">Open</property>
|
||||
25 </object>
|
||||
26 </child>
|
||||
27 <child>
|
||||
28 <object class="GtkLabel" id="dmy2">
|
||||
29 <property name="hexpand">TRUE</property>
|
||||
30 </object>
|
||||
31 </child>
|
||||
32 <child>
|
||||
33 <object class="GtkButton" id="btns">
|
||||
34 <property name="label">Save</property>
|
||||
35 </object>
|
||||
36 </child>
|
||||
37 <child>
|
||||
38 <object class="GtkButton" id="btnc">
|
||||
39 <property name="label">Close</property>
|
||||
40 </object>
|
||||
41 </child>
|
||||
42 <child>
|
||||
43 <object class="GtkLabel" id="dmy3">
|
||||
44 <property name="width-chars">10</property>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 </object>
|
||||
48 </child>
|
||||
49 <child>
|
||||
50 <object class="GtkNotebook" id="nb">
|
||||
51 <property name="hexpand">TRUE</property>
|
||||
52 <property name="vexpand">TRUE</property>
|
||||
53 </object>
|
||||
54 </child>
|
||||
55 </object>
|
||||
56 </child>
|
||||
57 </object>
|
||||
58 </interface>
|
||||
59
|
||||
~~~xml
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">file editor</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnn">
|
||||
19 <property name="label">New</property>
|
||||
20 </object>
|
||||
21 </child>
|
||||
22 <child>
|
||||
23 <object class="GtkButton" id="btno">
|
||||
24 <property name="label">Open</property>
|
||||
25 </object>
|
||||
26 </child>
|
||||
27 <child>
|
||||
28 <object class="GtkLabel" id="dmy2">
|
||||
29 <property name="hexpand">TRUE</property>
|
||||
30 </object>
|
||||
31 </child>
|
||||
32 <child>
|
||||
33 <object class="GtkButton" id="btns">
|
||||
34 <property name="label">Save</property>
|
||||
35 </object>
|
||||
36 </child>
|
||||
37 <child>
|
||||
38 <object class="GtkButton" id="btnc">
|
||||
39 <property name="label">Close</property>
|
||||
40 </object>
|
||||
41 </child>
|
||||
42 <child>
|
||||
43 <object class="GtkLabel" id="dmy3">
|
||||
44 <property name="width-chars">10</property>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 </object>
|
||||
48 </child>
|
||||
49 <child>
|
||||
50 <object class="GtkNotebook" id="nb">
|
||||
51 <property name="hexpand">TRUE</property>
|
||||
52 <property name="vexpand">TRUE</property>
|
||||
53 </object>
|
||||
54 </child>
|
||||
55 </object>
|
||||
56 </child>
|
||||
57 </object>
|
||||
58 </interface>
|
||||
59
|
||||
~~~
|
||||
|
||||
This is coded with XML structure.
|
||||
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 *build;
|
||||
~~~C
|
||||
GtkBuilder *build;
|
||||
|
||||
build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
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_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file.
|
||||
|
@ -295,54 +301,56 @@ Using ui file not only shortens C source files, but also makes the widgets' stru
|
|||
Now I'll show you the C source code `tfe3.c`.
|
||||
Only functions `on_open` are shown as follows.
|
||||
|
||||
1 static void
|
||||
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4 GtkWidget *nb;
|
||||
5 GtkWidget *lab;
|
||||
6 GtkNotebookPage *nbp;
|
||||
7 GtkWidget *scr;
|
||||
8 GtkWidget *tv;
|
||||
9 GtkTextBuffer *tb;
|
||||
10 char *contents;
|
||||
11 gsize length;
|
||||
12 char *filename;
|
||||
13 int i;
|
||||
14 GtkBuilder *build;
|
||||
15
|
||||
16 build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
17 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
18 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
19 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
20 g_object_unref(build);
|
||||
21 for (i = 0; i < n_files; i++) {
|
||||
22 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
23 scr = gtk_scrolled_window_new ();
|
||||
24 tv = tfe_text_view_new ();
|
||||
25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
27 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
28
|
||||
29 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
30 gtk_text_buffer_set_text (tb, contents, length);
|
||||
31 g_free (contents);
|
||||
32 filename = g_file_get_basename (files[i]);
|
||||
33 lab = gtk_label_new (filename);
|
||||
34 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
35 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
36 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
37 g_free (filename);
|
||||
38 } else {
|
||||
39 filename = g_file_get_path (files[i]);
|
||||
40 g_print ("No such file: %s.\n", filename);
|
||||
41 g_free (filename);
|
||||
42 }
|
||||
43 }
|
||||
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
45 gtk_widget_show (win);
|
||||
46 } else
|
||||
47 gtk_window_destroy (GTK_WINDOW (win));
|
||||
48 }
|
||||
~~~C
|
||||
1 static void
|
||||
2 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
3 GtkWidget *win;
|
||||
4 GtkWidget *nb;
|
||||
5 GtkWidget *lab;
|
||||
6 GtkNotebookPage *nbp;
|
||||
7 GtkWidget *scr;
|
||||
8 GtkWidget *tv;
|
||||
9 GtkTextBuffer *tb;
|
||||
10 char *contents;
|
||||
11 gsize length;
|
||||
12 char *filename;
|
||||
13 int i;
|
||||
14 GtkBuilder *build;
|
||||
15
|
||||
16 build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
17 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
18 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
19 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
20 g_object_unref(build);
|
||||
21 for (i = 0; i < n_files; i++) {
|
||||
22 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
23 scr = gtk_scrolled_window_new ();
|
||||
24 tv = tfe_text_view_new ();
|
||||
25 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
26 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
27 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
28
|
||||
29 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
30 gtk_text_buffer_set_text (tb, contents, length);
|
||||
31 g_free (contents);
|
||||
32 filename = g_file_get_basename (files[i]);
|
||||
33 lab = gtk_label_new (filename);
|
||||
34 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
35 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
36 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
37 g_free (filename);
|
||||
38 } else {
|
||||
39 filename = g_file_get_path (files[i]);
|
||||
40 g_print ("No such file: %s.\n", filename);
|
||||
41 g_free (filename);
|
||||
42 }
|
||||
43 }
|
||||
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
45 gtk_widget_show (win);
|
||||
46 } else
|
||||
47 gtk_window_destroy (GTK_WINDOW (win));
|
||||
48 }
|
||||
~~~
|
||||
|
||||
The source code of `tfe3.c` is stored in [src/tfe](https://github.com/ToshioCP/Gtk4-tutorial/tree/main/src/tfe) directory.
|
||||
If you want to see it, click the link above.
|
||||
|
@ -353,22 +361,24 @@ In the same way, you can get the source files below in the directory [src/tfe](h
|
|||
GtkBuilder can build widgets using string.
|
||||
Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file.
|
||||
|
||||
char *uistring;
|
||||
~~~C
|
||||
char *uistring;
|
||||
|
||||
uistring =
|
||||
"<interface>"
|
||||
"<object class="GtkApplicationWindow" id="win">"
|
||||
"<property name=\"title\">file editor</property>"
|
||||
"<property name=\"default-width\">600</property>"
|
||||
"<property name=\"default-height\">400</property>"
|
||||
"<child>"
|
||||
"<object class=\"GtkBox\" id=\"boxv\">"
|
||||
"<property name="orientation">GTK_ORIENTATION_VERTICAL</property>"
|
||||
... ... ...
|
||||
... ... ...
|
||||
"</interface>";
|
||||
uistring =
|
||||
"<interface>"
|
||||
"<object class="GtkApplicationWindow" id="win">"
|
||||
"<property name=\"title\">file editor</property>"
|
||||
"<property name=\"default-width\">600</property>"
|
||||
"<property name=\"default-height\">400</property>"
|
||||
"<child>"
|
||||
"<object class=\"GtkBox\" id=\"boxv\">"
|
||||
"<property name="orientation">GTK_ORIENTATION_VERTICAL</property>"
|
||||
... ... ...
|
||||
... ... ...
|
||||
"</interface>";
|
||||
|
||||
build = gtk_builder_new_from_stringfile (uistring);
|
||||
build = gtk_builder_new_from_stringfile (uistring);
|
||||
~~~
|
||||
|
||||
This method has an advantage and disadvantage.
|
||||
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`.
|
||||
It describes resource files.
|
||||
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
||||
4 <file>tfe3.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
||||
4 <file>tfe3.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~
|
||||
|
||||
- 2: gresources tag can include mulitple gresources (gresource tags).
|
||||
However, this xml has only one gresource.
|
||||
|
@ -441,12 +453,14 @@ Now run the compiler.
|
|||
Then a C source file `resources.c` is generated.
|
||||
Modify tfe3.c and save it as tfe3_r.c
|
||||
|
||||
# include "resources.c"
|
||||
... ... ...
|
||||
... ... ...
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
|
||||
... ... ...
|
||||
... ... ...
|
||||
~~~C
|
||||
#include "resources.c"
|
||||
... ... ...
|
||||
... ... ...
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
|
||||
... ... ...
|
||||
... ... ...
|
||||
~~~
|
||||
|
||||
Then, compile and run it.
|
||||
The window appears and it is the same as the screenshot at the beginning of this page.
|
||||
|
|
490
gfm/sec9.md
490
gfm/sec9.md
|
@ -42,201 +42,211 @@ All the source files are listed below.
|
|||
|
||||
`tfetextview.h`
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
4 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
5
|
||||
6 void
|
||||
7 tfe_text_view_set_file (TfeTextView *tv, GFile *f);
|
||||
8
|
||||
9 GFile *
|
||||
10 tfe_text_view_get_file (TfeTextView *tv);
|
||||
11
|
||||
12 GtkWidget *
|
||||
13 tfe_text_view_new (void);
|
||||
14
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
4 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
5
|
||||
6 void
|
||||
7 tfe_text_view_set_file (TfeTextView *tv, GFile *f);
|
||||
8
|
||||
9 GFile *
|
||||
10 tfe_text_view_get_file (TfeTextView *tv);
|
||||
11
|
||||
12 GtkWidget *
|
||||
13 tfe_text_view_new (void);
|
||||
14
|
||||
~~~
|
||||
|
||||
`tfetextview.c`
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2 #include "tfetextview.h"
|
||||
3
|
||||
4 struct _TfeTextView
|
||||
5 {
|
||||
6 GtkTextView parent;
|
||||
7 GFile *file;
|
||||
8 };
|
||||
9
|
||||
10 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
11
|
||||
12 static void
|
||||
13 tfe_text_view_init (TfeTextView *tv) {
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
18 }
|
||||
19
|
||||
20 void
|
||||
21 tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
22 tv -> file = f;
|
||||
23 }
|
||||
24
|
||||
25 GFile *
|
||||
26 tfe_text_view_get_file (TfeTextView *tv) {
|
||||
27 return tv -> file;
|
||||
28 }
|
||||
29
|
||||
30 GtkWidget *
|
||||
31 tfe_text_view_new (void) {
|
||||
32 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
33 }
|
||||
34
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2 #include "tfetextview.h"
|
||||
3
|
||||
4 struct _TfeTextView
|
||||
5 {
|
||||
6 GtkTextView parent;
|
||||
7 GFile *file;
|
||||
8 };
|
||||
9
|
||||
10 G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
11
|
||||
12 static void
|
||||
13 tfe_text_view_init (TfeTextView *tv) {
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
18 }
|
||||
19
|
||||
20 void
|
||||
21 tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
22 tv -> file = f;
|
||||
23 }
|
||||
24
|
||||
25 GFile *
|
||||
26 tfe_text_view_get_file (TfeTextView *tv) {
|
||||
27 return tv -> file;
|
||||
28 }
|
||||
29
|
||||
30 GtkWidget *
|
||||
31 tfe_text_view_new (void) {
|
||||
32 return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
33 }
|
||||
34
|
||||
~~~
|
||||
|
||||
`tfe.c`
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2 #include "tfetextview.h"
|
||||
3
|
||||
4 static void
|
||||
5 on_activate (GApplication *app, gpointer user_data) {
|
||||
6 g_print ("You need a filename argument.\n");
|
||||
7 }
|
||||
8
|
||||
9 static void
|
||||
10 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
11 GtkWidget *win;
|
||||
12 GtkWidget *nb;
|
||||
13 GtkWidget *lab;
|
||||
14 GtkNotebookPage *nbp;
|
||||
15 GtkWidget *scr;
|
||||
16 GtkWidget *tv;
|
||||
17 GtkTextBuffer *tb;
|
||||
18 char *contents;
|
||||
19 gsize length;
|
||||
20 char *filename;
|
||||
21 int i;
|
||||
22 GtkBuilder *build;
|
||||
23
|
||||
24 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe.ui");
|
||||
25 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
26 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
27 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
28 g_object_unref (build);
|
||||
29 for (i = 0; i < n_files; i++) {
|
||||
30 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
31 scr = gtk_scrolled_window_new ();
|
||||
32 tv = tfe_text_view_new ();
|
||||
33 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
34 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
35 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
36
|
||||
37 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
38 gtk_text_buffer_set_text (tb, contents, length);
|
||||
39 g_free (contents);
|
||||
40 filename = g_file_get_basename (files[i]);
|
||||
41 lab = gtk_label_new (filename);
|
||||
42 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
43 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
44 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
45 g_free (filename);
|
||||
46 } else {
|
||||
47 filename = g_file_get_path (files[i]);
|
||||
48 g_print ("No such file: %s.\n", filename);
|
||||
49 g_free (filename);
|
||||
50 }
|
||||
51 }
|
||||
52 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
53 gtk_widget_show (win);
|
||||
54 } else
|
||||
55 gtk_window_destroy (GTK_WINDOW (win));
|
||||
56 }
|
||||
57
|
||||
58 int
|
||||
59 main (int argc, char **argv) {
|
||||
60 GtkApplication *app;
|
||||
61 int stat;
|
||||
62
|
||||
63 app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
||||
64 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
65 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
66 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
67 g_object_unref (app);
|
||||
68 return stat;
|
||||
69 }
|
||||
70
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2 #include "tfetextview.h"
|
||||
3
|
||||
4 static void
|
||||
5 on_activate (GApplication *app, gpointer user_data) {
|
||||
6 g_print ("You need a filename argument.\n");
|
||||
7 }
|
||||
8
|
||||
9 static void
|
||||
10 on_open (GApplication *app, GFile ** files, gint n_files, gchar *hint, gpointer user_data) {
|
||||
11 GtkWidget *win;
|
||||
12 GtkWidget *nb;
|
||||
13 GtkWidget *lab;
|
||||
14 GtkNotebookPage *nbp;
|
||||
15 GtkWidget *scr;
|
||||
16 GtkWidget *tv;
|
||||
17 GtkTextBuffer *tb;
|
||||
18 char *contents;
|
||||
19 gsize length;
|
||||
20 char *filename;
|
||||
21 int i;
|
||||
22 GtkBuilder *build;
|
||||
23
|
||||
24 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe.ui");
|
||||
25 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
26 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
27 nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
28 g_object_unref (build);
|
||||
29 for (i = 0; i < n_files; i++) {
|
||||
30 if (g_file_load_contents (files[i], NULL, &contents, &length, NULL, NULL)) {
|
||||
31 scr = gtk_scrolled_window_new ();
|
||||
32 tv = tfe_text_view_new ();
|
||||
33 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
34 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
35 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
36
|
||||
37 tfe_text_view_set_file (TFE_TEXT_VIEW (tv), g_file_dup (files[i]));
|
||||
38 gtk_text_buffer_set_text (tb, contents, length);
|
||||
39 g_free (contents);
|
||||
40 filename = g_file_get_basename (files[i]);
|
||||
41 lab = gtk_label_new (filename);
|
||||
42 gtk_notebook_append_page (GTK_NOTEBOOK (nb), scr, lab);
|
||||
43 nbp = gtk_notebook_get_page (GTK_NOTEBOOK (nb), scr);
|
||||
44 g_object_set (nbp, "tab-expand", TRUE, NULL);
|
||||
45 g_free (filename);
|
||||
46 } else {
|
||||
47 filename = g_file_get_path (files[i]);
|
||||
48 g_print ("No such file: %s.\n", filename);
|
||||
49 g_free (filename);
|
||||
50 }
|
||||
51 }
|
||||
52 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
53 gtk_widget_show (win);
|
||||
54 } else
|
||||
55 gtk_window_destroy (GTK_WINDOW (win));
|
||||
56 }
|
||||
57
|
||||
58 int
|
||||
59 main (int argc, char **argv) {
|
||||
60 GtkApplication *app;
|
||||
61 int stat;
|
||||
62
|
||||
63 app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
||||
64 g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
65 g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
|
||||
66 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
67 g_object_unref (app);
|
||||
68 return stat;
|
||||
69 }
|
||||
70
|
||||
~~~
|
||||
|
||||
`tfe.ui`
|
||||
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">file editor</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnn">
|
||||
19 <property name="label">New</property>
|
||||
20 </object>
|
||||
21 </child>
|
||||
22 <child>
|
||||
23 <object class="GtkButton" id="btno">
|
||||
24 <property name="label">Open</property>
|
||||
25 </object>
|
||||
26 </child>
|
||||
27 <child>
|
||||
28 <object class="GtkLabel" id="dmy2">
|
||||
29 <property name="hexpand">TRUE</property>
|
||||
30 </object>
|
||||
31 </child>
|
||||
32 <child>
|
||||
33 <object class="GtkButton" id="btns">
|
||||
34 <property name="label">Save</property>
|
||||
35 </object>
|
||||
36 </child>
|
||||
37 <child>
|
||||
38 <object class="GtkButton" id="btnc">
|
||||
39 <property name="label">Close</property>
|
||||
40 </object>
|
||||
41 </child>
|
||||
42 <child>
|
||||
43 <object class="GtkLabel" id="dmy3">
|
||||
44 <property name="width-chars">10</property>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 </object>
|
||||
48 </child>
|
||||
49 <child>
|
||||
50 <object class="GtkNotebook" id="nb">
|
||||
51 <property name="hexpand">TRUE</property>
|
||||
52 <property name="vexpand">TRUE</property>
|
||||
53 </object>
|
||||
54 </child>
|
||||
55 </object>
|
||||
56 </child>
|
||||
57 </object>
|
||||
58 </interface>
|
||||
59
|
||||
~~~xml
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">file editor</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnn">
|
||||
19 <property name="label">New</property>
|
||||
20 </object>
|
||||
21 </child>
|
||||
22 <child>
|
||||
23 <object class="GtkButton" id="btno">
|
||||
24 <property name="label">Open</property>
|
||||
25 </object>
|
||||
26 </child>
|
||||
27 <child>
|
||||
28 <object class="GtkLabel" id="dmy2">
|
||||
29 <property name="hexpand">TRUE</property>
|
||||
30 </object>
|
||||
31 </child>
|
||||
32 <child>
|
||||
33 <object class="GtkButton" id="btns">
|
||||
34 <property name="label">Save</property>
|
||||
35 </object>
|
||||
36 </child>
|
||||
37 <child>
|
||||
38 <object class="GtkButton" id="btnc">
|
||||
39 <property name="label">Close</property>
|
||||
40 </object>
|
||||
41 </child>
|
||||
42 <child>
|
||||
43 <object class="GtkLabel" id="dmy3">
|
||||
44 <property name="width-chars">10</property>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 </object>
|
||||
48 </child>
|
||||
49 <child>
|
||||
50 <object class="GtkNotebook" id="nb">
|
||||
51 <property name="hexpand">TRUE</property>
|
||||
52 <property name="vexpand">TRUE</property>
|
||||
53 </object>
|
||||
54 </child>
|
||||
55 </object>
|
||||
56 </child>
|
||||
57 </object>
|
||||
58 </interface>
|
||||
59
|
||||
~~~
|
||||
|
||||
`tfe.gresource.xml`
|
||||
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
||||
4 <file>tfe.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/tfe3">
|
||||
4 <file>tfe.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~
|
||||
|
||||
## Make
|
||||
|
||||
|
@ -278,25 +288,27 @@ If the modification time of `sample.c` is older then the generation of `sample.o
|
|||
|
||||
The Makefile for `tfe` is as follows.
|
||||
|
||||
1 all: tfe
|
||||
2
|
||||
3 tfe: tfe.o tfetextview.o resources.o
|
||||
4 gcc -o tfe tfe.o tfetextview.o resources.o `pkg-config --libs gtk4`
|
||||
5
|
||||
6 tfe.o: tfe.c tfetextview.h
|
||||
7 gcc -c -o tfe.o `pkg-config --cflags gtk4` tfe.c
|
||||
8 tfetextview.o: tfetextview.c tfetextview.h
|
||||
9 gcc -c -o tfetextview.o `pkg-config --cflags gtk4` tfetextview.c
|
||||
10 resources.o: resources.c
|
||||
11 gcc -c -o resources.o `pkg-config --cflags gtk4` resources.c
|
||||
12
|
||||
13 resources.c: tfe.gresource.xml tfe.ui
|
||||
14 glib-compile-resources tfe.gresource.xml --target=resources.c --generate-source
|
||||
15
|
||||
16 .Phony: clean
|
||||
17
|
||||
18 clean:
|
||||
19 rm -f tfe tfe.o tfetextview.o resources.o resources.c
|
||||
~~~makefile
|
||||
1 all: tfe
|
||||
2
|
||||
3 tfe: tfe.o tfetextview.o resources.o
|
||||
4 gcc -o tfe tfe.o tfetextview.o resources.o `pkg-config --libs gtk4`
|
||||
5
|
||||
6 tfe.o: tfe.c tfetextview.h
|
||||
7 gcc -c -o tfe.o `pkg-config --cflags gtk4` tfe.c
|
||||
8 tfetextview.o: tfetextview.c tfetextview.h
|
||||
9 gcc -c -o tfetextview.o `pkg-config --cflags gtk4` tfetextview.c
|
||||
10 resources.o: resources.c
|
||||
11 gcc -c -o resources.o `pkg-config --cflags gtk4` resources.c
|
||||
12
|
||||
13 resources.c: tfe.gresource.xml tfe.ui
|
||||
14 glib-compile-resources tfe.gresource.xml --target=resources.c --generate-source
|
||||
15
|
||||
16 .Phony: clean
|
||||
17
|
||||
18 clean:
|
||||
19 rm -f tfe tfe.o tfetextview.o resources.o resources.c
|
||||
~~~
|
||||
|
||||
You only need to type `make`.
|
||||
|
||||
|
@ -324,31 +336,33 @@ However, Ruby is really sophisticated and recommendable script language.
|
|||
|
||||
Rake has task and file task, which is similar to target, prerequisite and recipe in make.
|
||||
|
||||
1 require 'rake/clean'
|
||||
2
|
||||
3 targetfile = "tfe"
|
||||
4 srcfiles = FileList["tfe.c", "tfetextview.c", "resources.c"]
|
||||
5 rscfile = srcfiles[2]
|
||||
6 objfiles = srcfiles.gsub(/.c$/, '.o')
|
||||
7
|
||||
8 CLEAN.include(targetfile, objfiles, rscfile)
|
||||
9
|
||||
10 task default: targetfile
|
||||
11
|
||||
12 file targetfile => objfiles do |t|
|
||||
13 sh "gcc -o #{t.name} #{t.prerequisites.join(' ')} `pkg-config --libs gtk4`"
|
||||
14 end
|
||||
15
|
||||
16 objfiles.each do |obj|
|
||||
17 src = obj.gsub(/.o$/,'.c')
|
||||
18 file obj => src do |t|
|
||||
19 sh "gcc -c -o #{t.name} `pkg-config --cflags gtk4` #{t.source}"
|
||||
20 end
|
||||
21 end
|
||||
22
|
||||
23 file rscfile => ["tfe.gresource.xml", "tfe.ui"] do |t|
|
||||
24 sh "glib-compile-resources #{t.prerequisites[0]} --target=#{t.name} --generate-source"
|
||||
25 end
|
||||
~~~ruby
|
||||
1 require 'rake/clean'
|
||||
2
|
||||
3 targetfile = "tfe"
|
||||
4 srcfiles = FileList["tfe.c", "tfetextview.c", "resources.c"]
|
||||
5 rscfile = srcfiles[2]
|
||||
6 objfiles = srcfiles.gsub(/.c$/, '.o')
|
||||
7
|
||||
8 CLEAN.include(targetfile, objfiles, rscfile)
|
||||
9
|
||||
10 task default: targetfile
|
||||
11
|
||||
12 file targetfile => objfiles do |t|
|
||||
13 sh "gcc -o #{t.name} #{t.prerequisites.join(' ')} `pkg-config --libs gtk4`"
|
||||
14 end
|
||||
15
|
||||
16 objfiles.each do |obj|
|
||||
17 src = obj.gsub(/.o$/,'.c')
|
||||
18 file obj => src do |t|
|
||||
19 sh "gcc -c -o #{t.name} `pkg-config --cflags gtk4` #{t.source}"
|
||||
20 end
|
||||
21 end
|
||||
22
|
||||
23 file rscfile => ["tfe.gresource.xml", "tfe.ui"] do |t|
|
||||
24 sh "glib-compile-resources #{t.prerequisites[0]} --target=#{t.name} --generate-source"
|
||||
25 end
|
||||
~~~
|
||||
|
||||
What `Rakefile` describes is almost same as `Makefile` in the previous subsection.
|
||||
|
||||
|
@ -380,16 +394,18 @@ Many developers are using meson and ninja now.
|
|||
|
||||
To use meson, you first need to write `meson.build` file.
|
||||
|
||||
1 project('tfe', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','tfe.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('tfe.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~meson
|
||||
1 project('tfe', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','tfe.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('tfe.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('tfe', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~
|
||||
|
||||
- 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.
|
||||
|
|
|
@ -45,16 +45,28 @@ require 'pathname'
|
|||
|
||||
# ---- Folding verbatim lines ----
|
||||
# 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.
|
||||
# Therefore, 'width' must be at least five.
|
||||
# Width must be positive integer.
|
||||
# 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
|
||||
src_buf = IO.readlines srcmd
|
||||
src_dir = File.dirname srcmd
|
||||
md_dir = File.dirname md
|
||||
# type is 'the type of the target', which is one of "markdown", "html" and "latex".
|
||||
type = md_dir == "." ? "markdown" : md_dir
|
||||
type = File.basename md_dir # gfm, html or latex
|
||||
|
||||
md_buf = []
|
||||
comflag = false
|
||||
|
@ -65,14 +77,16 @@ def src2md srcmd, md, width
|
|||
else
|
||||
md_buf << " $ "+line
|
||||
`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
|
||||
elsif line == "$$$\n"
|
||||
comflag = true
|
||||
elsif line =~ /^@@@\s+(\S+)\s*(.*)\s*$/
|
||||
elsif line =~ /^@@@\s+(\S+)\s*(.*)$/
|
||||
c_file = $1
|
||||
c_functions = $2.split(" ")
|
||||
c_functions = $2.strip.split(" ")
|
||||
if c_file =~ /^\// # absolute path
|
||||
c_file_buf = IO.readlines(c_file)
|
||||
else #relative path
|
||||
|
@ -108,38 +122,33 @@ def src2md srcmd, md, width
|
|||
end
|
||||
end
|
||||
end
|
||||
md_buf << "~~~#{lang(c_file)}\n"
|
||||
ln_width = tmp_buf.size.to_s.length
|
||||
n = 1
|
||||
tmp_buf.each do |l|
|
||||
l = sprintf(" %#{ln_width}d %s", n, l)
|
||||
md_buf << l
|
||||
l = sprintf("%#{ln_width}d %s", n, l)
|
||||
fold(l, width).each_line do |l2|
|
||||
md_buf << l2
|
||||
end
|
||||
n += 1
|
||||
end
|
||||
md_buf << "~~~\n"
|
||||
else
|
||||
md_buf << change_rel_link(line, src_dir, File.dirname(md))
|
||||
end
|
||||
end
|
||||
tmp_buf = md_buf
|
||||
md_buf = []
|
||||
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)
|
||||
line = change_rel_link(line, src_dir, md_dir)
|
||||
if type == "latex" # remove relative link
|
||||
line.gsub!(/(^|[^!])\[([^\]]*)\]\((?~http)\)/,"\\1\\2")
|
||||
else # type == "gfm" or "html", then remove size option from link to image files.
|
||||
line.gsub!(/(!\[[^\]]*\]\([^\)]*\)) *{width *= *\d*(|\.\d*)cm *height *= *\d*(|\.\d*)cm}/,"\\1")
|
||||
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.
|
||||
md_buf << line
|
||||
end
|
||||
md_buf << line
|
||||
end
|
||||
IO.write(md,md_buf.join)
|
||||
end
|
||||
|
||||
def change_rel_link line, src_dir, basedir
|
||||
p_basedir = Pathname.new basedir
|
||||
# Change the base of relative links from org_dir to new_dir
|
||||
def change_rel_link line, org_dir, new_dir
|
||||
p_new_dir = Pathname.new new_dir
|
||||
left = ""
|
||||
right = line
|
||||
while right =~ /(!?\[[^\]]*\])\(([^\)]*)\)/
|
||||
|
@ -150,11 +159,42 @@ def change_rel_link line, src_dir, basedir
|
|||
if name =~ /\[(S|s)ection (\d+)\]/
|
||||
link = "sec#{$2}.md"
|
||||
elsif ! (link =~ /^(http|\/)/)
|
||||
p_link = Pathname.new "#{src_dir}/#{link}"
|
||||
link = p_link.relative_path_from(p_basedir).to_s
|
||||
p_link = Pathname.new "#{org_dir}/#{link}"
|
||||
link = p_link.relative_path_from(p_new_dir).to_s
|
||||
end
|
||||
left += "#{name}(#{link})"
|
||||
end
|
||||
left + right
|
||||
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
|
||||
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");
|
||||
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
|
||||
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_green = g_menu_item_new ("Green", "win.color::green");
|
||||
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
|
||||
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);
|
||||
g_free (color);
|
||||
g_action_change_state (G_ACTION (action), parameter);
|
||||
|
|
119
src/sec18.src.md
119
src/sec18.src.md
|
@ -11,22 +11,26 @@ The same goes for menus.
|
|||
The ui file for menus has interface, menu tags.
|
||||
The file starts and ends with interface tag.
|
||||
|
||||
<interface>
|
||||
<menu id="menubar">
|
||||
</menu>
|
||||
</interface>
|
||||
~~~xml
|
||||
<interface>
|
||||
<menu id="menubar">
|
||||
</menu>
|
||||
</interface>
|
||||
~~~
|
||||
|
||||
`menu` tag corresponds to GMenu object.
|
||||
`id` attribute defines the name of the object.
|
||||
It will be refered by GtkBuilder.
|
||||
|
||||
<submenu>
|
||||
<attribute name="label">File</attribute>
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</submenu>
|
||||
~~~xml
|
||||
<submenu>
|
||||
<attribute name="label">File</attribute>
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</submenu>
|
||||
~~~
|
||||
|
||||
`item` tag corresponds to item in GMenu which has the same structure as GMenuItem.
|
||||
The item above has a label attribute.
|
||||
|
@ -38,15 +42,17 @@ The GMenuItem has a link to GMenu.
|
|||
|
||||
The ui file above can be described as follows.
|
||||
|
||||
<item>
|
||||
<attribute name="label">File</attribute>
|
||||
<link name="submenu">
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
~~~xml
|
||||
<item>
|
||||
<attribute name="label">File</attribute>
|
||||
<link name="submenu">
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
~~~
|
||||
|
||||
`link` tag expresses the link to submenu.
|
||||
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 *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
~~~C
|
||||
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
g_object_unref (builder);
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
g_object_unref (builder);
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
typedef struct _GActionEntry GActionEntry;
|
||||
|
||||
struct _GActionEntry
|
||||
{
|
||||
const gchar *name; /* action name */
|
||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data); /* activate handler */
|
||||
const gchar *parameter_type; /* the type of the parameter given as a single GVariant type string */
|
||||
const gchar *state; /* initial state given in GVariant text format */
|
||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data); /* change-state handler */
|
||||
/*< private >*/
|
||||
gsize padding[3];
|
||||
};
|
||||
~~~C
|
||||
typedef struct _GActionEntry GActionEntry;
|
||||
|
||||
struct _GActionEntry
|
||||
{
|
||||
/* action name */
|
||||
const gchar *name;
|
||||
/* activate handler */
|
||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
|
||||
/* the type of the parameter given as a single GVariant type string */
|
||||
const gchar *parameter_type;
|
||||
/* initial state given in GVariant text format */
|
||||
const gchar *state;
|
||||
/* change-state handler */
|
||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);
|
||||
/*< private >*/
|
||||
gsize padding[3];
|
||||
};
|
||||
~~~
|
||||
For example, the actions in the previous section are:
|
||||
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
~~~C
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
~~~
|
||||
|
||||
And `g_action_map_add_action_entries` does all the process instead of the functions you have needed.
|
||||
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
~~~C
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
|
||||
G_N_ELEMENTS (app_entries), app);
|
||||
~~~
|
||||
|
||||
The code above does:
|
||||
|
||||
|
@ -120,12 +139,14 @@ The code above does:
|
|||
|
||||
The same goes for the other actions.
|
||||
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
|
||||
~~~C
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,
|
||||
G_N_ELEMENTS (win_entries), win);
|
||||
~~~
|
||||
The code above does:
|
||||
|
||||
- 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.
|
||||
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:
|
||||
|
||||
|
|
|
@ -141,7 +141,8 @@ Modify `env.sh`.
|
|||
# compiler
|
||||
CPPFLAGS="-I$HOME/local/include"
|
||||
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
|
||||
# linker
|
||||
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".
|
||||
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.
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ Let's run it.
|
|||
|
||||
$ ./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.
|
||||
|
|
|
@ -55,39 +55,41 @@ So, I will just show you the way how to write the code and avoid the theoretical
|
|||
Let's define TfeTextView object which is a child object of GtkTextView.
|
||||
First, look at the program below.
|
||||
|
||||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
~~~C
|
||||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
|
||||
struct _TfeTextView
|
||||
{
|
||||
GtkTextView parent;
|
||||
GFile *file;
|
||||
};
|
||||
struct _TfeTextView
|
||||
{
|
||||
GtkTextView parent;
|
||||
GFile *file;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
|
||||
static void
|
||||
tfe_text_view_init (TfeTextView *tv) {
|
||||
}
|
||||
static void
|
||||
tfe_text_view_init (TfeTextView *tv) {
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
}
|
||||
static void
|
||||
tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
}
|
||||
|
||||
void
|
||||
tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
tv -> file = f;
|
||||
}
|
||||
void
|
||||
tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
|
||||
tv -> file = f;
|
||||
}
|
||||
|
||||
GFile *
|
||||
tfe_text_view_get_file (TfeTextView *tv) {
|
||||
return tv -> file;
|
||||
}
|
||||
GFile *
|
||||
tfe_text_view_get_file (TfeTextView *tv) {
|
||||
return tv -> file;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
tfe_text_view_new (void) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
}
|
||||
GtkWidget *
|
||||
tfe_text_view_new (void) {
|
||||
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.
|
||||
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
|
||||
|
||||
|
@ -71,12 +71,14 @@ Those two decribe the same structure of widgets.
|
|||
|
||||
GtkBuilder builds widgets based on the ui file.
|
||||
|
||||
GtkBuilder *build;
|
||||
~~~C
|
||||
GtkBuilder *build;
|
||||
|
||||
build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
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_get_object (build, "win")` returns the pointer to the widget `win`, which is the id in the ui file.
|
||||
|
@ -106,22 +108,24 @@ In the same way, you can get the source files below in the directory [src/tfe](h
|
|||
GtkBuilder can build widgets using string.
|
||||
Use the function gtk\_builder\_new\_from\_string instead of gtk\_builder\_new\_from\_file.
|
||||
|
||||
char *uistring;
|
||||
~~~C
|
||||
char *uistring;
|
||||
|
||||
uistring =
|
||||
"<interface>"
|
||||
"<object class="GtkApplicationWindow" id="win">"
|
||||
"<property name=\"title\">file editor</property>"
|
||||
"<property name=\"default-width\">600</property>"
|
||||
"<property name=\"default-height\">400</property>"
|
||||
"<child>"
|
||||
"<object class=\"GtkBox\" id=\"boxv\">"
|
||||
"<property name="orientation">GTK_ORIENTATION_VERTICAL</property>"
|
||||
... ... ...
|
||||
... ... ...
|
||||
"</interface>";
|
||||
uistring =
|
||||
"<interface>"
|
||||
"<object class="GtkApplicationWindow" id="win">"
|
||||
"<property name=\"title\">file editor</property>"
|
||||
"<property name=\"default-width\">600</property>"
|
||||
"<property name=\"default-height\">400</property>"
|
||||
"<child>"
|
||||
"<object class=\"GtkBox\" id=\"boxv\">"
|
||||
"<property name="orientation">GTK_ORIENTATION_VERTICAL</property>"
|
||||
... ... ...
|
||||
... ... ...
|
||||
"</interface>";
|
||||
|
||||
build = gtk_builder_new_from_stringfile (uistring);
|
||||
build = gtk_builder_new_from_stringfile (uistring);
|
||||
~~~
|
||||
|
||||
This method has an advantage and disadvantage.
|
||||
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.
|
||||
Modify tfe3.c and save it as tfe3_r.c
|
||||
|
||||
# include "resources.c"
|
||||
... ... ...
|
||||
... ... ...
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
|
||||
... ... ...
|
||||
... ... ...
|
||||
~~~C
|
||||
#include "resources.c"
|
||||
... ... ...
|
||||
... ... ...
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
|
||||
... ... ...
|
||||
... ... ...
|
||||
~~~
|
||||
|
||||
Then, compile and run it.
|
||||
The window appears and it is the same as the screenshot at the beginning of this page.
|
||||
|
|
Loading…
Reference in a new issue