2022-04-21 16:53:28 +02:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" / >
< meta name = "generator" content = "pandoc" / >
< meta name = "viewport" content = "width=device-width, initial-scale=1" / >
< link href = "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel = "stylesheet" integrity = "sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin = "anonymous" >
2022-11-21 14:48:20 +01:00
< title > GTK 4 tutorial< / title >
2022-04-21 16:53:28 +02:00
< style >
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre{overflow: visible;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
2022-04-17 13:54:42 +02:00
}
2022-04-21 16:53:28 +02:00
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::after
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
td {padding: 2px 6px; border: 1px solid;}
img {display: block; margin-left: auto; margin-right: auto;}
figcaption {text-align: center;}
< / style >
< / head >
< body style = "padding-top: 70px;" >
< div class = "container" >
< nav class = "navbar fixed-top navbar-expand-lg navbar-dark bg-primary" >
< div class = "container-fluid" >
< span class = "navbar-brand" > Gtk4 tutorial< / span >
< button class = "navbar-toggler" type = "button" data-bs-toggle = "collapse" data-bs-target = "#navbarSupportedContent" aria-controls = "navbarSupportedContent" aria-expanded = "false" aria-label = "Toggle navigation" >
< span class = "navbar-toggler-icon" > < / span >
< / button >
< div class = "collapse navbar-collapse" id = "navbarSupportedContent" >
< ul class = "navbar-nav me-auto mb-2 mb-lg-0" >
< li class = "nav-item" >
< a class = "nav-link" href = "index.html" > Home< / a >
< / li >
< li class = "nav-item" >
< a class = "nav-link" href = "sec12.html" > Prev: section12< / a >
< / li >
< li class = "nav-item" >
< a class = "nav-link" href = "sec14.html" > Next: section14< / a >
< / li >
< / ul >
< / div >
< / div >
< / nav >
2022-04-17 13:54:42 +02:00
< h1 id = "functions-in-tfetextview" > Functions in TfeTextView< / h1 >
< p > In this section I will explain functions in TfeTextView object.< / p >
< h2 id = "tfe.h-and-tfetextview.h" > tfe.h and tfetextview.h< / h2 >
2022-11-21 14:48:20 +01:00
< p > < code > tfe.h< / code > is a top header file and it includes
< code > gtk.h< / code > and all the header files. C source files
< code > tfeapplication.c< / code > and < code > tfenotebook.c< / code > include
< code > tfe.h< / code > at the beginning.< / p >
< div class = "sourceCode" id = "cb1" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb1-1" > < a href = "#cb1-1" > < / a > < span class = "pp" > #include < / span > < span class = "im" > < gtk/gtk.h> < / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb1-2" > < a href = "#cb1-2" > < / a > < / span >
< span id = "cb1-3" > < a href = "#cb1-3" > < / a > < span class = "pp" > #include < / span > < span class = "im" > " ../tfetextview/tfetextview.h" < / span > < / span >
< span id = "cb1-4" > < a href = "#cb1-4" > < / a > < span class = "pp" > #include < / span > < span class = "im" > " tfenotebook.h" < / span > < / span > < / code > < / pre > < / div >
2022-11-21 14:48:20 +01:00
< p > < code > ../tfetextview/tfetextview.h< / code > is a header file which
describes the public functions in < code > tfetextview.c< / code > .< / p >
< div class = "sourceCode" id = "cb2" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb2-1" > < a href = "#cb2-1" > < / a > < span class = "pp" > #ifndef __TFE_TEXT_VIEW_H__< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-2" > < a href = "#cb2-2" > < / a > < span class = "pp" > #define __TFE_TEXT_VIEW_H__< / span > < / span >
< span id = "cb2-3" > < a href = "#cb2-3" > < / a > < / span >
< span id = "cb2-4" > < a href = "#cb2-4" > < / a > < span class = "pp" > #include < / span > < span class = "im" > < gtk/gtk.h> < / span > < / span >
< span id = "cb2-5" > < a href = "#cb2-5" > < / a > < / span >
< span id = "cb2-6" > < a href = "#cb2-6" > < / a > < span class = "pp" > #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-7" > < a href = "#cb2-7" > < / a > G_DECLARE_FINAL_TYPE < span class = "op" > (< / span > TfeTextView< span class = "op" > ,< / span > tfe_text_view< span class = "op" > ,< / span > TFE< span class = "op" > ,< / span > TEXT_VIEW< span class = "op" > ,< / span > GtkTextView< span class = "op" > )< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-8" > < a href = "#cb2-8" > < / a > < / span >
< span id = "cb2-9" > < a href = "#cb2-9" > < / a > < span class = "co" > /* " open-response" signal response */< / span > < / span >
< span id = "cb2-10" > < a href = "#cb2-10" > < / a > < span class = "kw" > enum< / span > TfeTextViewOpenResponseType< / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-11" > < a href = "#cb2-11" > < / a > < span class = "op" > {< / span > < / span >
< span id = "cb2-12" > < a href = "#cb2-12" > < / a > TFE_OPEN_RESPONSE_SUCCESS< span class = "op" > ,< / span > < / span >
< span id = "cb2-13" > < a href = "#cb2-13" > < / a > TFE_OPEN_RESPONSE_CANCEL< span class = "op" > ,< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-14" > < a href = "#cb2-14" > < / a > TFE_OPEN_RESPONSE_ERROR< / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-15" > < a href = "#cb2-15" > < / a > < span class = "op" > };< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-16" > < a href = "#cb2-16" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-17" > < a href = "#cb2-17" > < / a > GFile < span class = "op" > *< / span > < / span >
< span id = "cb2-18" > < a href = "#cb2-18" > < / a > tfe_text_view_get_file < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-19" > < a href = "#cb2-19" > < / a > < / span >
< span id = "cb2-20" > < a href = "#cb2-20" > < / a > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-21" > < a href = "#cb2-21" > < / a > tfe_text_view_open < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > ,< / span > GtkWindow < span class = "op" > *< / span > win< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-22" > < a href = "#cb2-22" > < / a > < / span >
< span id = "cb2-23" > < a href = "#cb2-23" > < / a > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-24" > < a href = "#cb2-24" > < / a > tfe_text_view_save < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-25" > < a href = "#cb2-25" > < / a > < / span >
< span id = "cb2-26" > < a href = "#cb2-26" > < / a > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-27" > < a href = "#cb2-27" > < / a > tfe_text_view_saveas < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-28" > < a href = "#cb2-28" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-29" > < a href = "#cb2-29" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb2-30" > < a href = "#cb2-30" > < / a > tfe_text_view_new_with_file < span class = "op" > (< / span > GFile < span class = "op" > *< / span > file< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-31" > < a href = "#cb2-31" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb2-32" > < a href = "#cb2-32" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb2-33" > < a href = "#cb2-33" > < / a > tfe_text_view_new < span class = "op" > (< / span > < span class = "dt" > void< / span > < span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb2-34" > < a href = "#cb2-34" > < / a > < / span >
< span id = "cb2-35" > < a href = "#cb2-35" > < / a > < span class = "pp" > #endif < / span > < span class = "co" > /* __TFE_TEXT_VIEW_H__ */< / span > < / span > < / code > < / pre > < / div >
< ul >
2022-11-21 14:48:20 +01:00
< li > 1,2,35: Thanks to these three lines, the following lines are
included only once.< / li >
< li > 4: Includes gtk4 header files. The header file < code > gtk4< / code >
also has the same mechanism to avoid including it multiple times.< / li >
< li > 6-7: These two lines define TfeTextView type, its class structure
and some useful macros.< / li >
< li > 9-15: A definition of the value of the parameter of “open-response”
signal.< / li >
2022-04-17 13:54:42 +02:00
< li > 17-33: Declarations of public functions on TfeTextView.< / li >
< / ul >
2022-11-21 14:48:20 +01:00
< h2 id = "functions-to-create-tfetextview-instances" > Functions to create
TfeTextView instances< / h2 >
< p > A TfeTextView instance is created with < code > tfe_text_view_new< / code >
or < code > tfe_text_view_new_with_file< / code > .< / p >
< div class = "sourceCode" id = "cb3" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb3-1" > < a href = "#cb3-1" aria-hidden = "true" tabindex = "-1" > < / a > GtkWidget < span class = "op" > *< / span > tfe_text_view_new < span class = "op" > (< / span > < span class = "dt" > void< / span > < span class = "op" > );< / span > < / span > < / code > < / pre > < / div >
< p > < code > tfe_text_view_new< / code > just creates a new TfeTextView
instance and returns the pointer to the new instance.< / p >
< div class = "sourceCode" id = "cb4" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb4-1" > < a href = "#cb4-1" aria-hidden = "true" tabindex = "-1" > < / a > GtkWidget < span class = "op" > *< / span > tfe_text_view_new_with_file < span class = "op" > (< / span > GFile < span class = "op" > *< / span > file< span class = "op" > );< / span > < / span > < / code > < / pre > < / div >
< p > < code > tfe_text_view_new_with_file< / code > is given a Gfile object as
an argument and it loads the file into the GtkTextBuffer instance, then
returns the pointer to the new instance. If an error occurs during the
creation process, NULL is returned.< / p >
2022-04-17 13:54:42 +02:00
< p > Each function is defined as follows.< / p >
2022-11-21 14:48:20 +01:00
< div class = "sourceCode" id = "cb5" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb5-1" > < a href = "#cb5-1" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb5-2" > < a href = "#cb5-2" > < / a > tfe_text_view_new_with_file < span class = "op" > (< / span > GFile < span class = "op" > *< / span > file< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb5-3" > < a href = "#cb5-3" > < / a > g_return_val_if_fail < span class = "op" > (< / span > G_IS_FILE < span class = "op" > (< / span > file< span class = "op" > ),< / span > NULL< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb5-4" > < a href = "#cb5-4" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb5-5" > < a href = "#cb5-5" > < / a > GtkWidget < span class = "op" > *< / span > tv< span class = "op" > ;< / span > < / span >
< span id = "cb5-6" > < a href = "#cb5-6" > < / a > GtkTextBuffer < span class = "op" > *< / span > tb< span class = "op" > ;< / span > < / span >
< span id = "cb5-7" > < a href = "#cb5-7" > < / a > < span class = "dt" > char< / span > < span class = "op" > *< / span > contents< span class = "op" > ;< / span > < / span >
< span id = "cb5-8" > < a href = "#cb5-8" > < / a > gsize length< span class = "op" > ;< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb5-9" > < a href = "#cb5-9" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb5-10" > < a href = "#cb5-10" > < / a > < span class = "cf" > if< / span > < span class = "op" > (!< / span > g_file_load_contents < span class = "op" > (< / span > file< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > < span class = "op" > & < / span > contents< span class = "op" > ,< / span > < span class = "op" > & < / span > length< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > NULL< span class = "op" > ))< / span > < span class = "co" > /* read error */< / span > < / span >
< span id = "cb5-11" > < a href = "#cb5-11" > < / a > < span class = "cf" > return< / span > NULL< span class = "op" > ;< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb5-12" > < a href = "#cb5-12" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb5-13" > < a href = "#cb5-13" > < / a > < span class = "cf" > if< / span > < span class = "op" > ((< / span > tv < span class = "op" > =< / span > tfe_text_view_new< span class = "op" > ())< / span > < span class = "op" > !=< / span > NULL< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb5-14" > < a href = "#cb5-14" > < / a > tb < span class = "op" > =< / span > gtk_text_view_get_buffer < span class = "op" > (< / span > GTK_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
< span id = "cb5-15" > < a href = "#cb5-15" > < / a > gtk_text_buffer_set_text < span class = "op" > (< / span > tb< span class = "op" > ,< / span > contents< span class = "op" > ,< / span > length< span class = "op" > );< / span > < / span >
< span id = "cb5-16" > < a href = "#cb5-16" > < / a > TFE_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > )-> < / span > file < span class = "op" > =< / span > g_file_dup < span class = "op" > (< / span > file< span class = "op" > );< / span > < / span >
< span id = "cb5-17" > < a href = "#cb5-17" > < / a > gtk_text_buffer_set_modified < span class = "op" > (< / span > tb< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb5-18" > < a href = "#cb5-18" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb5-19" > < a href = "#cb5-19" > < / a > g_free < span class = "op" > (< / span > contents< span class = "op" > );< / span > < / span >
< span id = "cb5-20" > < a href = "#cb5-20" > < / a > < span class = "cf" > return< / span > tv< span class = "op" > ;< / span > < / span >
< span id = "cb5-21" > < a href = "#cb5-21" > < / a > < span class = "op" > }< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb5-22" > < a href = "#cb5-22" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb5-23" > < a href = "#cb5-23" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb5-24" > < a href = "#cb5-24" > < / a > tfe_text_view_new < span class = "op" > (< / span > < span class = "dt" > void< / span > < span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb5-25" > < a href = "#cb5-25" > < / a > < span class = "cf" > return< / span > GTK_WIDGET < span class = "op" > (< / span > g_object_new < span class = "op" > (< / span > TFE_TYPE_TEXT_VIEW< span class = "op" > ,< / span > NULL< span class = "op" > ));< / span > < / span >
< span id = "cb5-26" > < a href = "#cb5-26" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-04-17 13:54:42 +02:00
< ul >
2022-11-21 14:48:20 +01:00
< li > 23-25: < code > tfe_text_view_new< / code > function. Just returns the
value from the function < code > g_object_new< / code > but casts it to the
pointer to GtkWidget. Initialization is done in
< code > tfe_text_view_init< / code > which is called in the process of
< code > g_object_new< / code > function.< / li >
2022-04-17 13:54:42 +02:00
< li > 1-21: < code > tfe_text_view_new_with_file< / code > function.< / li >
2022-11-21 14:48:20 +01:00
< li > 3: < code > g_return_val_if_fail< / code > is described in < a
href="https://docs.gtk.org/glib/func.return_val_if_fail.html">GLib API
Reference, g_return_val_if_fail< / a > . And also < a
href="https://docs.gtk.org/glib/logging.html">GLib API Reference,
Message Logging< / a > . It tests whether the argument < code > file< / code > is
a pointer to GFile. If it’ s true, then the program goes on to the next
line. If it’ s false, then it returns NULL (the second argument)
immediately. And at the same time it logs out the error message (usually
the log is outputted to stderr or stdout). This function is used to
check the programmer’ s error. If an error occurs, the solution is
usually to change the (caller) program and fix the bug. You need to
distinguish programmer’ s errors and runtime errors. You shouldn’ t use
this function to find runtime errors.< / li >
< li > 10-11: If an error occurs when reading the file, then the function
returns NULL.< / li >
< li > 13: Calls the function < code > tfe_text_view_new< / code > . The function
creates TfeTextView instance and returns the pointer to the instance. If
an error happens in < code > tfe_text_view_new< / code > , it returns
NULL.< / li >
< li > 14: Gets the pointer to GtkTextBuffer corresponds to
< code > tv< / code > . The pointer is assigned to < code > tb< / code > < / li >
< li > 15: Assigns the contents read from the file to GtkTextBuffer pointed
by < code > tb< / code > .< / li >
< li > 16: Duplicates < code > file< / code > and sets < code > tv-> file< / code >
to point it.< / li >
< li > 17: The function
< code > gtk_text_buffer_set_modified (tb, FALSE)< / code > sets the
modification flag of < code > tb< / code > to FALSE. The modification flag
indicates that the contents of the buffer has been modified. It is used
when the contents are saved. If the modification flag is FALSE, it
doesn’ t need to save the contents.< / li >
2022-04-17 13:54:42 +02:00
< li > 19: Frees the memories pointed by < code > contents< / code > .< / li >
2022-11-21 14:48:20 +01:00
< li > 20: Returns < code > tv< / code > , which is a pointer to the newly created
TfeTextView instance. If an error happens, NULL is returned.< / li >
2022-04-17 13:54:42 +02:00
< / ul >
< h2 id = "save-and-saveas-functions" > Save and saveas functions< / h2 >
2022-11-21 14:48:20 +01:00
< p > Save and saveas functions write the contents in the GtkTextBuffer to
a file.< / p >
< div class = "sourceCode" id = "cb6" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb6-1" > < a href = "#cb6-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "dt" > void< / span > tfe_text_view_save < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < / span > < / code > < / pre > < / div >
< p > The function < code > tfe_text_view_save< / code > writes the contents in
the GtkTextBuffer to a file specified by < code > tv-> file< / code > . If
< code > tv-> file< / code > is NULL, then it shows GtkFileChooserDialog and
prompts the user to choose a file to save. Then it saves the contents to
the file and sets < code > tv-> file< / code > to point the GFile instance
for the file.< / p >
< div class = "sourceCode" id = "cb7" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb7-1" > < a href = "#cb7-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "dt" > void< / span > tfe_text_view_saveas < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < / span > < / code > < / pre > < / div >
< p > The function < code > saveas< / code > uses GtkFileChooserDialog and
prompts the user to select a existed file or specify a new file to save.
Then, the function changes < code > tv-> file< / code > and save the
contents to the specified file. If an error occurs, it is shown to the
user through the message dialog. The error is managed only in the
TfeTextView and no information is notified to the caller.< / p >
< div class = "sourceCode" id = "cb8" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb8-1" > < a href = "#cb8-1" > < / a > < span class = "dt" > static< / span > gboolean< / span >
< span id = "cb8-2" > < a href = "#cb8-2" > < / a > save_file < span class = "op" > (< / span > GFile < span class = "op" > *< / span > file< span class = "op" > ,< / span > GtkTextBuffer < span class = "op" > *< / span > tb< span class = "op" > ,< / span > GtkWindow < span class = "op" > *< / span > win< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-3" > < a href = "#cb8-3" > < / a > GtkTextIter start_iter< span class = "op" > ;< / span > < / span >
< span id = "cb8-4" > < a href = "#cb8-4" > < / a > GtkTextIter end_iter< span class = "op" > ;< / span > < / span >
< span id = "cb8-5" > < a href = "#cb8-5" > < / a > gchar < span class = "op" > *< / span > contents< span class = "op" > ;< / span > < / span >
< span id = "cb8-6" > < a href = "#cb8-6" > < / a > gboolean stat< span class = "op" > ;< / span > < / span >
< span id = "cb8-7" > < a href = "#cb8-7" > < / a > GtkWidget < span class = "op" > *< / span > message_dialog< span class = "op" > ;< / span > < / span >
< span id = "cb8-8" > < a href = "#cb8-8" > < / a > GError < span class = "op" > *< / span > err < span class = "op" > =< / span > NULL< span class = "op" > ;< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-9" > < a href = "#cb8-9" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-10" > < a href = "#cb8-10" > < / a > gtk_text_buffer_get_bounds < span class = "op" > (< / span > tb< span class = "op" > ,< / span > < span class = "op" > & < / span > start_iter< span class = "op" > ,< / span > < span class = "op" > & < / span > end_iter< span class = "op" > );< / span > < / span >
< span id = "cb8-11" > < a href = "#cb8-11" > < / a > contents < span class = "op" > =< / span > gtk_text_buffer_get_text < span class = "op" > (< / span > tb< span class = "op" > ,< / span > < span class = "op" > & < / span > start_iter< span class = "op" > ,< / span > < span class = "op" > & < / span > end_iter< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb8-12" > < a href = "#cb8-12" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > g_file_replace_contents < span class = "op" > (< / span > file< span class = "op" > ,< / span > contents< span class = "op" > ,< / span > strlen < span class = "op" > (< / span > contents< span class = "op" > ),< / span > NULL< span class = "op" > ,< / span > TRUE< span class = "op" > ,< / span > G_FILE_CREATE_NONE< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > < span class = "op" > & < / span > err< span class = "op" > ))< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-13" > < a href = "#cb8-13" > < / a > gtk_text_buffer_set_modified < span class = "op" > (< / span > tb< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb8-14" > < a href = "#cb8-14" > < / a > stat < span class = "op" > =< / span > TRUE< span class = "op" > ;< / span > < / span >
< span id = "cb8-15" > < a href = "#cb8-15" > < / a > < span class = "op" > }< / span > < span class = "cf" > else< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-16" > < a href = "#cb8-16" > < / a > message_dialog < span class = "op" > =< / span > gtk_message_dialog_new < span class = "op" > (< / span > win< span class = "op" > ,< / span > GTK_DIALOG_MODAL< span class = "op" > ,< / span > < / span >
< span id = "cb8-17" > < a href = "#cb8-17" > < / a > GTK_MESSAGE_ERROR< span class = "op" > ,< / span > GTK_BUTTONS_CLOSE< span class = "op" > ,< / span > < / span >
< span id = "cb8-18" > < a href = "#cb8-18" > < / a > < span class = "st" > " %s.< / span > < span class = "sc" > \n< / span > < span class = "st" > " < / span > < span class = "op" > ,< / span > err< span class = "op" > -> < / span > message< span class = "op" > );< / span > < / span >
< span id = "cb8-19" > < a href = "#cb8-19" > < / a > g_signal_connect < span class = "op" > (< / span > message_dialog< span class = "op" > ,< / span > < span class = "st" > " response" < / span > < span class = "op" > ,< / span > G_CALLBACK < span class = "op" > (< / span > gtk_window_destroy< span class = "op" > ),< / span > NULL< span class = "op" > );< / span > < / span >
< span id = "cb8-20" > < a href = "#cb8-20" > < / a > gtk_widget_show < span class = "op" > (< / span > message_dialog< span class = "op" > );< / span > < / span >
< span id = "cb8-21" > < a href = "#cb8-21" > < / a > g_error_free < span class = "op" > (< / span > err< span class = "op" > );< / span > < / span >
< span id = "cb8-22" > < a href = "#cb8-22" > < / a > stat < span class = "op" > =< / span > FALSE< span class = "op" > ;< / span > < / span >
< span id = "cb8-23" > < a href = "#cb8-23" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb8-24" > < a href = "#cb8-24" > < / a > g_free < span class = "op" > (< / span > contents< span class = "op" > );< / span > < / span >
< span id = "cb8-25" > < a href = "#cb8-25" > < / a > < span class = "cf" > return< / span > stat< span class = "op" > ;< / span > < / span >
< span id = "cb8-26" > < a href = "#cb8-26" > < / a > < span class = "op" > }< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-27" > < a href = "#cb8-27" > < / a > < / span >
< span id = "cb8-28" > < a href = "#cb8-28" > < / a > < span class = "dt" > static< / span > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-29" > < a href = "#cb8-29" > < / a > saveas_dialog_response < span class = "op" > (< / span > GtkWidget < span class = "op" > *< / span > dialog< span class = "op" > ,< / span > gint response< span class = "op" > ,< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-30" > < a href = "#cb8-30" > < / a > GtkTextBuffer < span class = "op" > *< / span > tb < span class = "op" > =< / span > gtk_text_view_get_buffer < span class = "op" > (< / span > GTK_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
< span id = "cb8-31" > < a href = "#cb8-31" > < / a > GFile < span class = "op" > *< / span > file< span class = "op" > ;< / span > < / span >
< span id = "cb8-32" > < a href = "#cb8-32" > < / a > GtkWidget < span class = "op" > *< / span > win < span class = "op" > =< / span > gtk_widget_get_ancestor < span class = "op" > (< / span > GTK_WIDGET < span class = "op" > (< / span > tv< span class = "op" > ),< / span > GTK_TYPE_WINDOW< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-33" > < a href = "#cb8-33" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-34" > < a href = "#cb8-34" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > response < span class = "op" > ==< / span > GTK_RESPONSE_ACCEPT< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-35" > < a href = "#cb8-35" > < / a > file < span class = "op" > =< / span > gtk_file_chooser_get_file < span class = "op" > (< / span > GTK_FILE_CHOOSER < span class = "op" > (< / span > dialog< span class = "op" > ));< / span > < / span >
< span id = "cb8-36" > < a href = "#cb8-36" > < / a > < span class = "cf" > if< / span > < span class = "op" > (!< / span > G_IS_FILE < span class = "op" > (< / span > file< span class = "op" > ))< / span > < / span >
< span id = "cb8-37" > < a href = "#cb8-37" > < / a > g_warning < span class = "op" > (< / span > < span class = "st" > " TfeTextView: gtk_file_chooser_get_file returns non GFile.< / span > < span class = "sc" > \n< / span > < span class = "st" > " < / span > < span class = "op" > );< / span > < / span >
< span id = "cb8-38" > < a href = "#cb8-38" > < / a > < span class = "cf" > else< / span > < span class = "cf" > if< / span > < span class = "op" > (< / span > save_file< span class = "op" > (< / span > file< span class = "op" > ,< / span > tb< span class = "op" > ,< / span > GTK_WINDOW < span class = "op" > (< / span > win< span class = "op" > )))< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-39" > < a href = "#cb8-39" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > G_IS_FILE < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ))< / span > < / span >
< span id = "cb8-40" > < a href = "#cb8-40" > < / a > g_object_unref < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > );< / span > < / span >
< span id = "cb8-41" > < a href = "#cb8-41" > < / a > tv< span class = "op" > -> < / span > file < span class = "op" > =< / span > file< span class = "op" > ;< / span > < / span >
< span id = "cb8-42" > < a href = "#cb8-42" > < / a > g_signal_emit < span class = "op" > (< / span > tv< span class = "op" > ,< / span > tfe_text_view_signals< span class = "op" > [< / span > CHANGE_FILE< span class = "op" > ],< / span > < span class = "dv" > 0< / span > < span class = "op" > );< / span > < / span >
< span id = "cb8-43" > < a href = "#cb8-43" > < / a > < span class = "op" > }< / span > < span class = "cf" > else< / span > < / span >
< span id = "cb8-44" > < a href = "#cb8-44" > < / a > g_object_unref < span class = "op" > (< / span > file< span class = "op" > );< / span > < / span >
< span id = "cb8-45" > < a href = "#cb8-45" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb8-46" > < a href = "#cb8-46" > < / a > gtk_window_destroy < span class = "op" > (< / span > GTK_WINDOW < span class = "op" > (< / span > dialog< span class = "op" > ));< / span > < / span >
< span id = "cb8-47" > < a href = "#cb8-47" > < / a > < span class = "op" > }< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-48" > < a href = "#cb8-48" > < / a > < / span >
< span id = "cb8-49" > < a href = "#cb8-49" > < / a > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-50" > < a href = "#cb8-50" > < / a > tfe_text_view_save < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-51" > < a href = "#cb8-51" > < / a > g_return_if_fail < span class = "op" > (< / span > TFE_IS_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-52" > < a href = "#cb8-52" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-53" > < a href = "#cb8-53" > < / a > GtkTextBuffer < span class = "op" > *< / span > tb < span class = "op" > =< / span > gtk_text_view_get_buffer < span class = "op" > (< / span > GTK_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
< span id = "cb8-54" > < a href = "#cb8-54" > < / a > GtkWidget < span class = "op" > *< / span > win < span class = "op" > =< / span > gtk_widget_get_ancestor < span class = "op" > (< / span > GTK_WIDGET < span class = "op" > (< / span > tv< span class = "op" > ),< / span > GTK_TYPE_WINDOW< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-55" > < a href = "#cb8-55" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-56" > < a href = "#cb8-56" > < / a > < span class = "cf" > if< / span > < span class = "op" > (!< / span > gtk_text_buffer_get_modified < span class = "op" > (< / span > tb< span class = "op" > ))< / span > < / span >
< span id = "cb8-57" > < a href = "#cb8-57" > < / a > < span class = "cf" > return< / span > < span class = "op" > ;< / span > < span class = "co" > /* no need to save it */< / span > < / span >
< span id = "cb8-58" > < a href = "#cb8-58" > < / a > < span class = "cf" > else< / span > < span class = "cf" > if< / span > < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file < span class = "op" > ==< / span > NULL< span class = "op" > )< / span > < / span >
< span id = "cb8-59" > < a href = "#cb8-59" > < / a > tfe_text_view_saveas < span class = "op" > (< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb8-60" > < a href = "#cb8-60" > < / a > < span class = "cf" > else< / span > < span class = "cf" > if< / span > < span class = "op" > (!< / span > G_IS_FILE < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ))< / span > < / span >
< span id = "cb8-61" > < a href = "#cb8-61" > < / a > g_error < span class = "op" > (< / span > < span class = "st" > " TfeTextView: The pointer tv-> file isn' t NULL nor GFile.< / span > < span class = "sc" > \n< / span > < span class = "st" > " < / span > < span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-62" > < a href = "#cb8-62" > < / a > < span class = "cf" > else< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-63" > < a href = "#cb8-63" > < / a > save_file < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ,< / span > tb< span class = "op" > ,< / span > GTK_WINDOW < span class = "op" > (< / span > win< span class = "op" > ));< / span > < / span >
< span id = "cb8-64" > < a href = "#cb8-64" > < / a > < span class = "op" > }< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-65" > < a href = "#cb8-65" > < / a > < / span >
< span id = "cb8-66" > < a href = "#cb8-66" > < / a > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-67" > < a href = "#cb8-67" > < / a > tfe_text_view_saveas < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-68" > < a href = "#cb8-68" > < / a > g_return_if_fail < span class = "op" > (< / span > TFE_IS_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-69" > < a href = "#cb8-69" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-70" > < a href = "#cb8-70" > < / a > GtkWidget < span class = "op" > *< / span > dialog< span class = "op" > ;< / span > < / span >
< span id = "cb8-71" > < a href = "#cb8-71" > < / a > GtkWidget < span class = "op" > *< / span > win < span class = "op" > =< / span > gtk_widget_get_ancestor < span class = "op" > (< / span > GTK_WIDGET < span class = "op" > (< / span > tv< span class = "op" > ),< / span > GTK_TYPE_WINDOW< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb8-72" > < a href = "#cb8-72" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb8-73" > < a href = "#cb8-73" > < / a > dialog < span class = "op" > =< / span > gtk_file_chooser_dialog_new < span class = "op" > (< / span > < span class = "st" > " Save file" < / span > < span class = "op" > ,< / span > GTK_WINDOW < span class = "op" > (< / span > win< span class = "op" > ),< / span > GTK_FILE_CHOOSER_ACTION_SAVE< span class = "op" > ,< / span > < / span >
< span id = "cb8-74" > < a href = "#cb8-74" > < / a > < span class = "st" > " Cancel" < / span > < span class = "op" > ,< / span > GTK_RESPONSE_CANCEL< span class = "op" > ,< / span > < / span >
< span id = "cb8-75" > < a href = "#cb8-75" > < / a > < span class = "st" > " Save" < / span > < span class = "op" > ,< / span > GTK_RESPONSE_ACCEPT< span class = "op" > ,< / span > < / span >
< span id = "cb8-76" > < a href = "#cb8-76" > < / a > NULL< span class = "op" > );< / span > < / span >
< span id = "cb8-77" > < a href = "#cb8-77" > < / a > g_signal_connect < span class = "op" > (< / span > dialog< span class = "op" > ,< / span > < span class = "st" > " response" < / span > < span class = "op" > ,< / span > G_CALLBACK < span class = "op" > (< / span > saveas_dialog_response< span class = "op" > ),< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb8-78" > < a href = "#cb8-78" > < / a > gtk_widget_show < span class = "op" > (< / span > dialog< span class = "op" > );< / span > < / span >
< span id = "cb8-79" > < a href = "#cb8-79" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-04-17 13:54:42 +02:00
< ul >
2022-11-21 14:48:20 +01:00
< li > 1-26: < code > save_file< / code > function. This function is called from
< code > saveas_dialog_response< / code > and < code > tfe_text_view_save< / code > .
This function saves the contents of the buffer to the file given as an
argument. If error happens, it displays an error message. The class of
this function is < code > static< / code > . Therefore, only functions in this
file (< code > tfeTetview.c< / code > ) call this function. Such static
functions usally don’ t have < code > g_return_val_if_fail< / code >
function.< / li >
2022-04-17 13:54:42 +02:00
< li > 10-11: Gets the text contents from the buffer.< / li >
2022-11-21 14:48:20 +01:00
< li > 12-14: Saves the contents to the file. If no error happens, set the
modified flag to be FALSE. This means that the buffer is not modified
since it has been saved. And set the return status < code > stat< / code > to
be TRUE.< / li >
< li > 15-23: If it fails to save the contents, displays an error
message.< / li >
2022-04-17 13:54:42 +02:00
< li > 16-18: Creates a message dialog with the error message.< / li >
2022-11-21 14:48:20 +01:00
< li > 19: Connects the “response” signal to
< code > gtk_window_destroy< / code > , so that the dialog disappears when a
user clicked on the button.< / li >
< li > 20-21: Shows the window, frees < code > err< / code > and set
< code > stat< / code > to be FLASE.< / li >
2022-04-17 13:54:42 +02:00
< li > 24: Frees < code > contents< / code > .< / li >
< li > 25: Returns to the caller.< / li >
2022-11-21 14:48:20 +01:00
< li > 28-47: < code > saveas_dialog_response< / code > function. This is a
signal handler for the “response” signal on GtkFileChooserDialog
instance created by < code > tfe_text_view_saveas< / code > function. This
handler analyzes the response and determines whether to save the
contents.< / li >
< li > 34-45: If the response is < code > GTK_RESPONSE_ACCEPT< / code > , the user
has clicked on the < code > Save< / code > button. So, it tries to save.< / li >
2022-04-17 13:54:42 +02:00
< li > 35: Gets the GFile < code > file< / code > from GtkFileChooserDialog.< / li >
2022-11-21 14:48:20 +01:00
< li > 36-37: If it doesn’ t point GFile, it outputs an error message to the
log.< / li >
< li > 38: Otherwise, it calls < code > save_file< / code > to save the contents
to the file.< / li >
< li > 39-42: If < code > save_file< / code > has successfully saved the
contents, < code > tv-> file< / code > is updated. If the old GFile pointed
by < code > tv-> file< / code > exists, it is freed in advance. Emits
“change-file” signal.< / li >
2022-04-17 13:54:42 +02:00
< li > 44: Unrefs < code > file< / code > .< / li >
< li > 46: destroys the file chooser dialog.< / li >
< li > 49-64: < code > tfe_text_view_save< / code > function.< / li >
2022-11-21 14:48:20 +01:00
< li > 51: < code > tfe_text_view_save< / code > is public, i.e. it is open to
the other files. So, it doesn’ t have < code > static< / code > class. Public
functions should check the parameter type with
< code > g_return_if_fail< / code > function. If < code > tv< / code > is not a
pointer to a TfeTextView instance, then it logs an error message and
immediately returns. This function is similar to
< code > g_return_val_if_fail< / code > , but no value is returned because
< code > tfe_text_view_save< / code > doesn’ t return a value.< / li >
< li > 53-54: Gets GtkTextBuffer instance and GtkWidget instance and
assignes them to < code > tb< / code > and< code > win< / code > respectively.< / li >
< li > 56-57: If the buffer hasn’ t modified, then it doesn’ t need to save
it. So the function returns.< / li >
< li > 58-59: If < code > tv-> file< / code > is NULL, no file has given yet.
It calls < code > tfe_text_view_saveas< / code > which prompts a user to
select a file or specify a new file to save.< / li >
< li > 60-61: If < code > tv-> file< / code > doesn’ t point GFile, somethig bad
has happened. Logs an error message.< / li >
< li > 62-63: Calls < code > save_file< / code > to save the contents to the
file.< / li >
< li > 66-79: < code > tfe_text_view_saveas< / code > function. It shows
GtkFileChooserDialog and prompts the user to choose a file.< / li >
< li > 73-76: Creates GtkFileChooserDialog. The title is “Save file”.
Transient parent of the dialog is < code > win< / code > , which is the
top-level window. The action is save mode. The buttons are Cancel and
Save.< / li >
< li > 77: connects the “response” signal of the dialog and
< code > saveas_dialog_response< / code > handler.< / li >
2022-04-17 13:54:42 +02:00
< li > 78: Shows the dialog.< / li >
< / ul >
< figure >
2022-11-21 14:48:20 +01:00
< img src = "image/saveas.png" alt = "Saveas process" / >
< figcaption aria-hidden = "true" > Saveas process< / figcaption >
2022-04-17 13:54:42 +02:00
< / figure >
2022-11-21 14:48:20 +01:00
< p > When you use GtkFileChooserDialog, you need to divide the program
into two parts. One is a function which creates GtkFileChooserDialog and
the other is a signal handler. The function just creates and shows
GtkFileChooserDialog. The rest is done by the handler. It gets Gfile
from GtkFileChooserDialog and saves the buffer to the file by calling
< code > save_file< / code > .< / p >
2022-04-17 13:54:42 +02:00
< h2 id = "open-function" > Open function< / h2 >
2022-11-21 14:48:20 +01:00
< p > Open function shows GtkFileChooserDialog to users and prompts them to
choose a file. Then it reads the file and puts the text into
GtkTextBuffer.< / p >
< div class = "sourceCode" id = "cb9" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb9-1" > < a href = "#cb9-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "dt" > void< / span > tfe_text_view_open < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > ,< / span > GtkWindow < span class = "op" > *< / span > win< span class = "op" > );< / span > < / span > < / code > < / pre > < / div >
< p > The parameter < code > win< / code > is the top-level window. It will be a
transient parent window of GtkFileChooserDialog when the dialog is
created. This allows window managers to keep the dialog on top of the
parent window, or center the dialog over the parent window. It is
possible to give no parent window to the dialog. However, it is
encouraged to give a parent window to dialog. This function might be
called just after < code > tv< / code > has been created. In that case,
< code > tv< / code > has not been incorporated into the widget hierarchy.
Therefore it is impossible to get the top-level window from
< code > tv< / code > . That’ s why the function needs < code > win< / code >
parameter.< / p >
< p > This function is usually called when the buffer of < code > tv< / code > is
empty. However, even if the buffer is not empty,
< code > tfe_text_view_open< / code > doesn’ t treat it as an error. If you
want to revert the buffer, calling this function is appropriate.
Otherwise probably bad things will happen.< / p >
< div class = "sourceCode" id = "cb10" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb10-1" > < a href = "#cb10-1" > < / a > < span class = "dt" > static< / span > < span class = "dt" > void< / span > < / span >
< span id = "cb10-2" > < a href = "#cb10-2" > < / a > open_dialog_response< span class = "op" > (< / span > GtkWidget < span class = "op" > *< / span > dialog< span class = "op" > ,< / span > gint response< span class = "op" > ,< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb10-3" > < a href = "#cb10-3" > < / a > GtkTextBuffer < span class = "op" > *< / span > tb < span class = "op" > =< / span > gtk_text_view_get_buffer < span class = "op" > (< / span > GTK_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
< span id = "cb10-4" > < a href = "#cb10-4" > < / a > GFile < span class = "op" > *< / span > file< span class = "op" > ;< / span > < / span >
< span id = "cb10-5" > < a href = "#cb10-5" > < / a > < span class = "dt" > char< / span > < span class = "op" > *< / span > contents< span class = "op" > ;< / span > < / span >
< span id = "cb10-6" > < a href = "#cb10-6" > < / a > gsize length< span class = "op" > ;< / span > < / span >
< span id = "cb10-7" > < a href = "#cb10-7" > < / a > GtkWidget < span class = "op" > *< / span > message_dialog< span class = "op" > ;< / span > < / span >
< span id = "cb10-8" > < a href = "#cb10-8" > < / a > GError < span class = "op" > *< / span > err < span class = "op" > =< / span > NULL< span class = "op" > ;< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb10-9" > < a href = "#cb10-9" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb10-10" > < a href = "#cb10-10" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > response < span class = "op" > !=< / span > GTK_RESPONSE_ACCEPT< span class = "op" > )< / span > < / span >
< span id = "cb10-11" > < a href = "#cb10-11" > < / a > g_signal_emit < span class = "op" > (< / span > tv< span class = "op" > ,< / span > tfe_text_view_signals< span class = "op" > [< / span > OPEN_RESPONSE< span class = "op" > ],< / span > < span class = "dv" > 0< / span > < span class = "op" > ,< / span > TFE_OPEN_RESPONSE_CANCEL< span class = "op" > );< / span > < / span >
< span id = "cb10-12" > < a href = "#cb10-12" > < / a > < span class = "cf" > else< / span > < span class = "cf" > if< / span > < span class = "op" > (!< / span > G_IS_FILE < span class = "op" > (< / span > file < span class = "op" > =< / span > gtk_file_chooser_get_file < span class = "op" > (< / span > GTK_FILE_CHOOSER < span class = "op" > (< / span > dialog< span class = "op" > ))))< / span > < span class = "op" > {< / span > < / span >
< span id = "cb10-13" > < a href = "#cb10-13" > < / a > g_warning < span class = "op" > (< / span > < span class = "st" > " TfeTextView: gtk_file_chooser_get_file returns non GFile.< / span > < span class = "sc" > \n< / span > < span class = "st" > " < / span > < span class = "op" > );< / span > < / span >
< span id = "cb10-14" > < a href = "#cb10-14" > < / a > g_signal_emit < span class = "op" > (< / span > tv< span class = "op" > ,< / span > tfe_text_view_signals< span class = "op" > [< / span > OPEN_RESPONSE< span class = "op" > ],< / span > < span class = "dv" > 0< / span > < span class = "op" > ,< / span > TFE_OPEN_RESPONSE_ERROR< span class = "op" > );< / span > < / span >
< span id = "cb10-15" > < a href = "#cb10-15" > < / a > < span class = "op" > }< / span > < span class = "cf" > else< / span > < span class = "cf" > if< / span > < span class = "op" > (!< / span > g_file_load_contents < span class = "op" > (< / span > file< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > < span class = "op" > & < / span > contents< span class = "op" > ,< / span > < span class = "op" > & < / span > length< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > < span class = "op" > & < / span > err< span class = "op" > ))< / span > < span class = "op" > {< / span > < span class = "co" > /* read error */< / span > < / span >
< span id = "cb10-16" > < a href = "#cb10-16" > < / a > g_object_unref < span class = "op" > (< / span > file< span class = "op" > );< / span > < / span >
< span id = "cb10-17" > < a href = "#cb10-17" > < / a > message_dialog < span class = "op" > =< / span > gtk_message_dialog_new < span class = "op" > (< / span > GTK_WINDOW < span class = "op" > (< / span > dialog< span class = "op" > ),< / span > GTK_DIALOG_MODAL< span class = "op" > ,< / span > < / span >
< span id = "cb10-18" > < a href = "#cb10-18" > < / a > GTK_MESSAGE_ERROR< span class = "op" > ,< / span > GTK_BUTTONS_CLOSE< span class = "op" > ,< / span > < / span >
< span id = "cb10-19" > < a href = "#cb10-19" > < / a > < span class = "st" > " %s.< / span > < span class = "sc" > \n< / span > < span class = "st" > " < / span > < span class = "op" > ,< / span > err< span class = "op" > -> < / span > message< span class = "op" > );< / span > < / span >
< span id = "cb10-20" > < a href = "#cb10-20" > < / a > g_signal_connect < span class = "op" > (< / span > message_dialog< span class = "op" > ,< / span > < span class = "st" > " response" < / span > < span class = "op" > ,< / span > G_CALLBACK < span class = "op" > (< / span > gtk_window_destroy< span class = "op" > ),< / span > NULL< span class = "op" > );< / span > < / span >
< span id = "cb10-21" > < a href = "#cb10-21" > < / a > gtk_widget_show < span class = "op" > (< / span > message_dialog< span class = "op" > );< / span > < / span >
< span id = "cb10-22" > < a href = "#cb10-22" > < / a > g_error_free < span class = "op" > (< / span > err< span class = "op" > );< / span > < / span >
< span id = "cb10-23" > < a href = "#cb10-23" > < / a > g_signal_emit < span class = "op" > (< / span > tv< span class = "op" > ,< / span > tfe_text_view_signals< span class = "op" > [< / span > OPEN_RESPONSE< span class = "op" > ],< / span > < span class = "dv" > 0< / span > < span class = "op" > ,< / span > TFE_OPEN_RESPONSE_ERROR< span class = "op" > );< / span > < / span >
< span id = "cb10-24" > < a href = "#cb10-24" > < / a > < span class = "op" > }< / span > < span class = "cf" > else< / span > < span class = "op" > {< / span > < / span >
< span id = "cb10-25" > < a href = "#cb10-25" > < / a > gtk_text_buffer_set_text < span class = "op" > (< / span > tb< span class = "op" > ,< / span > contents< span class = "op" > ,< / span > length< span class = "op" > );< / span > < / span >
< span id = "cb10-26" > < a href = "#cb10-26" > < / a > g_free < span class = "op" > (< / span > contents< span class = "op" > );< / span > < / span >
< span id = "cb10-27" > < a href = "#cb10-27" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > G_IS_FILE < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ))< / span > < / span >
< span id = "cb10-28" > < a href = "#cb10-28" > < / a > g_object_unref < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > );< / span > < / span >
< span id = "cb10-29" > < a href = "#cb10-29" > < / a > tv< span class = "op" > -> < / span > file < span class = "op" > =< / span > file< span class = "op" > ;< / span > < / span >
< span id = "cb10-30" > < a href = "#cb10-30" > < / a > gtk_text_buffer_set_modified < span class = "op" > (< / span > tb< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb10-31" > < a href = "#cb10-31" > < / a > g_signal_emit < span class = "op" > (< / span > tv< span class = "op" > ,< / span > tfe_text_view_signals< span class = "op" > [< / span > OPEN_RESPONSE< span class = "op" > ],< / span > < span class = "dv" > 0< / span > < span class = "op" > ,< / span > TFE_OPEN_RESPONSE_SUCCESS< span class = "op" > );< / span > < / span >
< span id = "cb10-32" > < a href = "#cb10-32" > < / a > g_signal_emit < span class = "op" > (< / span > tv< span class = "op" > ,< / span > tfe_text_view_signals< span class = "op" > [< / span > CHANGE_FILE< span class = "op" > ],< / span > < span class = "dv" > 0< / span > < span class = "op" > );< / span > < / span >
< span id = "cb10-33" > < a href = "#cb10-33" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb10-34" > < a href = "#cb10-34" > < / a > gtk_window_destroy < span class = "op" > (< / span > GTK_WINDOW < span class = "op" > (< / span > dialog< span class = "op" > ));< / span > < / span >
< span id = "cb10-35" > < a href = "#cb10-35" > < / a > < span class = "op" > }< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb10-36" > < a href = "#cb10-36" > < / a > < / span >
< span id = "cb10-37" > < a href = "#cb10-37" > < / a > < span class = "dt" > void< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb10-38" > < a href = "#cb10-38" > < / a > tfe_text_view_open < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > ,< / span > GtkWindow < span class = "op" > *< / span > win< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb10-39" > < a href = "#cb10-39" > < / a > g_return_if_fail < span class = "op" > (< / span > TFE_IS_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
< span id = "cb10-40" > < a href = "#cb10-40" > < / a > g_return_if_fail < span class = "op" > (< / span > GTK_IS_WINDOW < span class = "op" > (< / span > win< span class = "op" > ));< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb10-41" > < a href = "#cb10-41" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb10-42" > < a href = "#cb10-42" > < / a > GtkWidget < span class = "op" > *< / span > dialog< span class = "op" > ;< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb10-43" > < a href = "#cb10-43" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb10-44" > < a href = "#cb10-44" > < / a > dialog < span class = "op" > =< / span > gtk_file_chooser_dialog_new < span class = "op" > (< / span > < span class = "st" > " Open file" < / span > < span class = "op" > ,< / span > win< span class = "op" > ,< / span > GTK_FILE_CHOOSER_ACTION_OPEN< span class = "op" > ,< / span > < / span >
< span id = "cb10-45" > < a href = "#cb10-45" > < / a > < span class = "st" > " Cancel" < / span > < span class = "op" > ,< / span > GTK_RESPONSE_CANCEL< span class = "op" > ,< / span > < / span >
< span id = "cb10-46" > < a href = "#cb10-46" > < / a > < span class = "st" > " Open" < / span > < span class = "op" > ,< / span > GTK_RESPONSE_ACCEPT< span class = "op" > ,< / span > < / span >
< span id = "cb10-47" > < a href = "#cb10-47" > < / a > NULL< span class = "op" > );< / span > < / span >
< span id = "cb10-48" > < a href = "#cb10-48" > < / a > g_signal_connect < span class = "op" > (< / span > dialog< span class = "op" > ,< / span > < span class = "st" > " response" < / span > < span class = "op" > ,< / span > G_CALLBACK < span class = "op" > (< / span > open_dialog_response< span class = "op" > ),< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb10-49" > < a href = "#cb10-49" > < / a > gtk_widget_show < span class = "op" > (< / span > dialog< span class = "op" > );< / span > < / span >
< span id = "cb10-50" > < a href = "#cb10-50" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-04-17 13:54:42 +02:00
< ul >
< li > 37-50: < code > tfe_text_view_open< / code > function.< / li >
2022-11-21 14:48:20 +01:00
< li > 44-47: Creates GtkFileChooserDialog. The title is “Open file”.
Transient parent window is the top-level window of the application,
which is given by the caller. The action is open mode. The buttons are
Cancel and Open.< / li >
< li > 48: connects the “response” signal of the dialog and
< code > open_dialog_response< / code > signal handler.< / li >
2022-04-17 13:54:42 +02:00
< li > 49: Shows the dialog.< / li >
< li > 1-35: < code > open_dialog_response< / code > signal handler.< / li >
2022-11-21 14:48:20 +01:00
< li > 10-11: If the response from GtkFileChooserDialog is not
< code > GTK_RESPONSE_ACCEPT< / code > , the user has clicked on the “Cancel”
button or close button on the header bar. Then, “open-response” signal
is emitted. The parameter of the signal is
< code > TFE_OPEN_RESPONSE_CANCEL< / code > .< / li >
< li > 12-14: Gets the pointer to the Gfile by
< code > gtk_file_chooser_get_file< / code > . If it doesn’ t point GFile, maybe
an error has occurred. Then it emits “open-response” signal with the
parameter < code > TFE_OPEN_RESPONSE_ERROR< / code > .< / li >
< li > 15-23: If an error occurs at file reading, then it decreases the
reference count of the Gfile, shows a message dialog to report the error
to the user and emits “open-response” signal with the parameter
< code > TFE_OPEN_RESPONSE_ERROR< / code > .< / li >
< li > 24-33: If the file has successfully been read, then the text is
inserted to GtkTextBuffer, frees the temporary buffer pointed by
< code > contents< / code > and sets < code > tv-> file< / code > to point the
file (no duplication is not necessary). Then, it emits “open-response”
signal with the parameter < code > TFE_OPEN_RESPONSE_SUCCESS< / code > and
emits “change-file” signal.< / li >
2022-04-17 13:54:42 +02:00
< li > 34: destroys GtkFileCooserDialog.< / li >
< / ul >
2022-11-21 14:48:20 +01:00
< p > Now let’ s think about the whole process between the caller and
TfeTextView. It is shown in the following diagram and you would think
that it is really complicated. Because signal is the only way for
GtkFileChooserDialog to communicate with others. In GTK 3,
< code > gtk_dialog_run< / code > function is available. It simplifies the
process. However, in GTK 4, < code > gtk_dialog_run< / code > is unavailable
any more.< / p >
2022-04-17 13:54:42 +02:00
< figure >
2022-11-21 14:48:20 +01:00
< img src = "image/open.png" alt = "Caller and TfeTextView" / >
< figcaption aria-hidden = "true" > Caller and TfeTextView< / figcaption >
2022-04-17 13:54:42 +02:00
< / figure >
< ol type = "1" >
2022-11-21 14:48:20 +01:00
< li > A caller gets a pointer < code > tv< / code > to a TfeTextView instance by
calling < code > tfe_text_view_new< / code > .< / li >
< li > The caller connects the handler (left bottom in the diagram) and the
signal “open-response”.< / li >
< li > It calls < code > tfe_text_view_open< / code > to prompt the user to
select a file from GtkFileChooserDialog.< / li >
< li > The dialog emits a signal and it invokes the handler
< code > open_dialog_response< / code > .< / li >
< li > The handler reads the file and inserts the text into GtkTextBuffer
and emits a signal to inform the status as a response code.< / li >
2022-04-17 13:54:42 +02:00
< li > The handler out of the TfeTextView receives the signal.< / li >
< / ol >
< h2 id = "getting-gfile" > Getting Gfile< / h2 >
2022-11-21 14:48:20 +01:00
< p > < code > gtk_text_view_get_file< / code > is a simple function shown as
follows.< / p >
< div class = "sourceCode" id = "cb11" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb11-1" > < a href = "#cb11-1" > < / a > GFile < span class = "op" > *< / span > < / span >
< span id = "cb11-2" > < a href = "#cb11-2" > < / a > tfe_text_view_get_file < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb11-3" > < a href = "#cb11-3" > < / a > g_return_val_if_fail < span class = "op" > (< / span > TFE_IS_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ),< / span > NULL< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb11-4" > < a href = "#cb11-4" > < / a > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb11-5" > < a href = "#cb11-5" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > G_IS_FILE < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ))< / span > < / span >
< span id = "cb11-6" > < a href = "#cb11-6" > < / a > < span class = "cf" > return< / span > g_file_dup < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > );< / span > < / span >
2022-04-17 13:54:42 +02:00
< span id = "cb11-7" > < a href = "#cb11-7" > < / a > < span class = "cf" > else< / span > < / span >
2022-11-21 14:48:20 +01:00
< span id = "cb11-8" > < a href = "#cb11-8" > < / a > < span class = "cf" > return< / span > NULL< span class = "op" > ;< / span > < / span >
< span id = "cb11-9" > < a href = "#cb11-9" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
< p > The important thing is to duplicate < code > tv-> file< / code > .
Otherwise, if the caller frees the GFile object,
< code > tv-> file< / code > is no more guaranteed to point the GFile.
Another reason to use < code > g_file_dup< / code > is that GFile isn’ t
thread-safe. If you use GFile in the different thread, the duplication
is necessary. See < a
href="https://docs.gtk.org/gio/method.File.dup.html">Gio API Reference,
g_file_dup< / a > .< / p >
< h2 id = "the-api-document-and-source-file-of-tfetextview.c" > The API
document and source file of tfetextview.c< / h2 >
< p > Refer API document of TfeTextView. Its original markdown file is
under the directory < code > src/tfetextview< / code > .< / p >
< p > All the source files are listed in < a href = "sec16.html" > Section
16< / a > . You can find them under src/tfe5 and src/tfetextview
directories.< / p >
2022-04-21 16:53:28 +02:00
< / div >
< script src = "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity = "sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin = "anonymous" > < / script >
< / body >
< / html >