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 >
2023-07-15 10:27:53 +02:00
< h1 id = "tfetextview-class" > TfeTextView class< / h1 >
< p > The TfeTextView class will be finally completed in this section. The
remaining topic is functions. TfeTextView functions, which are
constructors and instance methods, are described in this section.< / p >
< p > The source files are in the directory < code > src/tfetextview< / code > .
You can get them by downloading the < a
href="https://github.com/ToshioCP/Gtk4-tutorial">repository< / a > .< / p >
2022-12-21 14:31:33 +01:00
< h2 id = "tfetextview.h" > tfetextview.h< / h2 >
< p > The header file < code > tfetextview.h< / code > provides:< / p >
< ul >
< li > The type of TfeTextView, which is
< code > TFE_TYPE_TEXT_VIEW< / code > .< / li >
2023-07-15 10:27:53 +02:00
< li > The macro < code > G_DECLARE_FINAL_TYPE< / code > , the expansion of which
includes some useful functions and definitions.< / li >
< li > Constants for the < code > open-response< / code > signal.< / li >
< li > Public functions of < code > tfetextview.c< / code > . They are
constructors and instance methods.< / li >
2022-12-21 14:31:33 +01:00
< / ul >
< p > Therefore, Any programs use TfeTextView needs to include
< code > tfetextview.h< / code > .< / p >
2022-11-21 14:48:20 +01:00
< div class = "sourceCode" id = "cb1" > < pre
2023-07-15 10:27:53 +02:00
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb1-1" > < a href = "#cb1-1" > < / a > < span class = "pp" > #pragma once< / span > < / span >
< 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" > < gtk/gtk.h> < / span > < / span >
< span id = "cb1-4" > < a href = "#cb1-4" > < / a > < / span >
< span id = "cb1-5" > < a href = "#cb1-5" > < / a > < span class = "pp" > #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()< / span > < / span >
< span id = "cb1-6" > < a href = "#cb1-6" > < / 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 >
< span id = "cb1-7" > < a href = "#cb1-7" > < / a > < / span >
< span id = "cb1-8" > < a href = "#cb1-8" > < / a > < span class = "co" > /* " open-response" signal response */< / span > < / span >
< span id = "cb1-9" > < a href = "#cb1-9" > < / a > < span class = "kw" > enum< / span > TfeTextViewOpenResponseType< / span >
< span id = "cb1-10" > < a href = "#cb1-10" > < / a > < span class = "op" > {< / span > < / span >
< span id = "cb1-11" > < a href = "#cb1-11" > < / a > TFE_OPEN_RESPONSE_SUCCESS< span class = "op" > ,< / span > < / span >
< span id = "cb1-12" > < a href = "#cb1-12" > < / a > TFE_OPEN_RESPONSE_CANCEL< span class = "op" > ,< / span > < / span >
< span id = "cb1-13" > < a href = "#cb1-13" > < / a > TFE_OPEN_RESPONSE_ERROR< / span >
< span id = "cb1-14" > < a href = "#cb1-14" > < / a > < span class = "op" > };< / span > < / span >
< span id = "cb1-15" > < a href = "#cb1-15" > < / a > < / span >
< span id = "cb1-16" > < a href = "#cb1-16" > < / a > GFile < span class = "op" > *< / span > < / span >
< span id = "cb1-17" > < a href = "#cb1-17" > < / a > tfe_text_view_get_file < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb1-18" > < a href = "#cb1-18" > < / a > < / span >
< span id = "cb1-19" > < a href = "#cb1-19" > < / a > < span class = "dt" > void< / span > < / span >
< span id = "cb1-20" > < a href = "#cb1-20" > < / 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 >
< span id = "cb1-21" > < a href = "#cb1-21" > < / a > < / span >
< span id = "cb1-22" > < a href = "#cb1-22" > < / a > < span class = "dt" > void< / span > < / span >
< span id = "cb1-23" > < a href = "#cb1-23" > < / a > tfe_text_view_save < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb1-24" > < a href = "#cb1-24" > < / a > < / span >
< span id = "cb1-25" > < a href = "#cb1-25" > < / a > < span class = "dt" > void< / span > < / span >
< span id = "cb1-26" > < a href = "#cb1-26" > < / a > tfe_text_view_saveas < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb1-27" > < a href = "#cb1-27" > < / a > < / span >
< span id = "cb1-28" > < a href = "#cb1-28" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb1-29" > < a href = "#cb1-29" > < / a > tfe_text_view_new_with_file < span class = "op" > (< / span > GFile < span class = "op" > *< / span > file< span class = "op" > );< / span > < / span >
< span id = "cb1-30" > < a href = "#cb1-30" > < / a > < / span >
< span id = "cb1-31" > < a href = "#cb1-31" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb1-32" > < a href = "#cb1-32" > < / a > tfe_text_view_new < span class = "op" > (< / span > < span class = "dt" > void< / span > < span class = "op" > );< / span > < / span > < / code > < / pre > < / div >
2022-04-17 13:54:42 +02:00
< ul >
2023-07-15 10:27:53 +02:00
< li > 1: The preprocessor directive < code > #pragma once< / code > makes the
header file be included only once. It is non-standard but widely
used.< / li >
< li > 3: Includes gtk4 header files. The header file < code > gtk4< / code >
also has the same mechanism to avoid being included multiple times.< / li >
< li > 5-6: These two lines define TfeTextView type, its class structure
and some useful definitions.
2022-12-21 14:31:33 +01:00
< ul >
< li > < code > TfeTextView< / code > and < code > TfeTextViewClass< / code > are
declared as typedef of C structures.< / li >
< li > You need to define a structure < code > _TfeTextView< / code > later.< / li >
< li > The class structure < code > _TfeTextViewClass< / code > is defined here.
You don’ t need to define it by yourself.< / li >
< li > Convenience functions < code > TFE_TEXT_VIEW ()< / code > for casting and
< code > TFE_IS_TEXT_VIEW< / code > for type check are defined.< / li >
< / ul > < / li >
2023-07-15 10:27:53 +02:00
< li > 8-14: A definition of the values of the “open-response” signal
parameters.< / li >
< li > 16-32: Declarations of public functions on TfeTextView.< / li >
2022-04-17 13:54:42 +02:00
< / ul >
2023-07-15 10:27:53 +02:00
< h2 id = "constructors" > Constructors< / h2 >
2022-11-21 14:48:20 +01:00
< p > A TfeTextView instance is created with < code > tfe_text_view_new< / code >
2023-07-15 10:27:53 +02:00
or < code > tfe_text_view_new_with_file< / code > . These functions are called
constructors.< / p >
2022-12-21 14:31:33 +01:00
< div class = "sourceCode" id = "cb2" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb2-1" > < a href = "#cb2-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 >
2023-07-15 10:27:53 +02:00
< p > It just creates a new TfeTextView instance and returns the pointer to
the new instance.< / p >
2022-12-21 14:31:33 +01:00
< 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_with_file < span class = "op" > (< / span > GFile < span class = "op" > *< / span > file< span class = "op" > );< / span > < / span > < / code > < / pre > < / div >
2023-07-15 10:27:53 +02:00
< p > It 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. The argument < code > file< / code > is owned by the caller and the
function doesn’ t change it. If an error occurs during the creation
process, NULL will be returned.< / p >
2022-04-17 13:54:42 +02:00
< p > Each function is defined as follows.< / p >
2022-12-21 14:31:33 +01:00
< div class = "sourceCode" id = "cb4" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb4-1" > < a href = "#cb4-1" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb4-2" > < a href = "#cb4-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 = "cb4-3" > < a href = "#cb4-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 >
< span id = "cb4-4" > < a href = "#cb4-4" > < / a > < / span >
< span id = "cb4-5" > < a href = "#cb4-5" > < / a > GtkWidget < span class = "op" > *< / span > tv< span class = "op" > ;< / span > < / span >
< span id = "cb4-6" > < a href = "#cb4-6" > < / a > GtkTextBuffer < span class = "op" > *< / span > tb< span class = "op" > ;< / span > < / span >
< span id = "cb4-7" > < a href = "#cb4-7" > < / a > < span class = "dt" > char< / span > < span class = "op" > *< / span > contents< span class = "op" > ;< / span > < / span >
< span id = "cb4-8" > < a href = "#cb4-8" > < / a > gsize length< span class = "op" > ;< / span > < / span >
< span id = "cb4-9" > < a href = "#cb4-9" > < / a > < / span >
< span id = "cb4-10" > < a href = "#cb4-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 = "cb4-11" > < a href = "#cb4-11" > < / a > < span class = "cf" > return< / span > NULL< span class = "op" > ;< / span > < / span >
< span id = "cb4-12" > < a href = "#cb4-12" > < / a > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb4-13" > < a href = "#cb4-13" > < / a > tv < span class = "op" > =< / span > tfe_text_view_new< span class = "op" > ();< / span > < / span >
< span id = "cb4-14" > < a href = "#cb4-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 = "cb4-15" > < a href = "#cb4-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 = "cb4-16" > < a href = "#cb4-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 = "cb4-17" > < a href = "#cb4-17" > < / a > gtk_text_buffer_set_modified < span class = "op" > (< / span > tb< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb4-18" > < a href = "#cb4-18" > < / a > g_free < span class = "op" > (< / span > contents< span class = "op" > );< / span > < / span >
< span id = "cb4-19" > < a href = "#cb4-19" > < / a > < span class = "cf" > return< / span > tv< span class = "op" > ;< / span > < / span >
< span id = "cb4-20" > < a href = "#cb4-20" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb4-21" > < a href = "#cb4-21" > < / a > < / span >
< span id = "cb4-22" > < a href = "#cb4-22" > < / a > GtkWidget < span class = "op" > *< / span > < / span >
< span id = "cb4-23" > < a href = "#cb4-23" > < / 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 = "cb4-24" > < a href = "#cb4-24" > < / 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 > < span class = "st" > " wrap-mode" < / span > < span class = "op" > ,< / span > GTK_WRAP_WORD_CHAR< span class = "op" > ,< / span > NULL< span class = "op" > ));< / span > < / span >
< span id = "cb4-25" > < a href = "#cb4-25" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-04-17 13:54:42 +02:00
< ul >
2023-07-15 10:27:53 +02:00
< li > 22-25: < code > tfe_text_view_new< / code > function. Just returns the
2022-11-21 14:48:20 +01:00
value from the function < code > g_object_new< / code > but casts it to the
2022-12-21 14:31:33 +01:00
pointer to GtkWidget. The function < code > g_object_new< / code > creates any
instances of its descendant class. The arguments are the type of the
2023-07-15 10:27:53 +02:00
class, property list and NULL, which is the end mark of the property
2022-12-21 14:31:33 +01:00
list. TfeTextView “wrap-mode” property has GTK_WRAP_WORD_CHAR as the
default value.< / li >
2023-07-15 10:27:53 +02:00
< li > 1-20: < 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
2022-12-21 14:31:33 +01:00
Reference – g_return_val_if_fail< / a > . And also < a
href="https://docs.gtk.org/glib/logging.html">GLib API Reference –
2022-11-21 14:48:20 +01:00
Message Logging< / a > . It tests whether the argument < code > file< / code > is
2023-07-15 10:27:53 +02:00
a pointer to GFile. If it’ s true, the program goes on to the next line.
If it’ s false, 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: Reads the file. If an error occurs, NULL is returned.< / li >
2022-11-21 14:48:20 +01:00
< li > 13: Calls the function < code > tfe_text_view_new< / code > . The function
2023-07-15 10:27:53 +02:00
creates TfeTextView instance and returns the pointer to the
instance.< / li >
< li > 14: Gets the pointer to the GtkTextBuffer instance corresponds to
2022-11-21 14:48:20 +01:00
< code > tv< / code > . The pointer is assigned to < code > tb< / code > < / li >
2023-07-15 10:27:53 +02:00
< li > 15: Assigns the contents read from the file to < code > tb< / code > .< / li >
2022-11-21 14:48:20 +01:00
< li > 16: Duplicates < code > file< / code > and sets < code > tv-> file< / code >
2023-07-15 10:27:53 +02:00
to point it. GFile is < em > not< / em > thread safe. The duplication makes
sure that the GFile instance of < code > tv< / code > keeps the file
information even if the original one is changed by other thread.< / li >
2022-11-21 14:48:20 +01:00
< 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
2023-07-15 10:27:53 +02:00
indicates that the contents 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 >
< li > 18: Frees the memories pointed by < code > contents< / code > .< / li >
< li > 19: Returns < code > tv< / code > , which is a pointer to the newly created
2022-11-21 14:48:20 +01:00
TfeTextView instance. If an error happens, NULL is returned.< / li >
2022-04-17 13:54:42 +02:00
< / ul >
2023-07-15 10:27:53 +02:00
< 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 >
2022-12-21 14:31:33 +01:00
< div class = "sourceCode" id = "cb5" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb5-1" > < a href = "#cb5-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 >
2022-11-21 14:48:20 +01:00
< 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
2023-07-15 10:27:53 +02:00
< code > tv-> file< / code > is NULL, then it shows file chooser dialog and
2022-11-21 14:48:20 +01:00
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 >
2022-12-21 14:31:33 +01:00
< 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_saveas < span class = "op" > (< / span > TfeTextView < span class = "op" > *< / span > tv< span class = "op" > )< / span > < / span > < / code > < / pre > < / div >
2023-07-15 10:27:53 +02:00
< p > The function < code > saveas< / code > shows a file chooser dialog and
2022-11-21 14:48:20 +01:00
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
2023-07-15 10:27:53 +02:00
user through the alert dialog. The error is managed only in the
2022-11-21 14:48:20 +01:00
TfeTextView and no information is notified to the caller.< / p >
2022-12-21 14:31:33 +01:00
< h3 id = "save_file-function" > save_file function< / h3 >
< div class = "sourceCode" id = "cb7" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb7-1" > < a href = "#cb7-1" > < / a > < span class = "dt" > static< / span > gboolean< / span >
< span id = "cb7-2" > < a href = "#cb7-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 = "cb7-3" > < a href = "#cb7-3" > < / a > GtkTextIter start_iter< span class = "op" > ;< / span > < / span >
< span id = "cb7-4" > < a href = "#cb7-4" > < / a > GtkTextIter end_iter< span class = "op" > ;< / span > < / span >
< span id = "cb7-5" > < a href = "#cb7-5" > < / a > < span class = "dt" > char< / span > < span class = "op" > *< / span > contents< span class = "op" > ;< / span > < / span >
< span id = "cb7-6" > < a href = "#cb7-6" > < / a > gboolean stat< span class = "op" > ;< / span > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb7-7" > < a href = "#cb7-7" > < / a > GtkAlertDialog < span class = "op" > *< / span > alert_dialog< span class = "op" > ;< / span > < / span >
2022-12-21 14:31:33 +01:00
< span id = "cb7-8" > < a href = "#cb7-8" > < / a > GError < span class = "op" > *< / span > err < span class = "op" > =< / span > NULL< span class = "op" > ;< / span > < / span >
< span id = "cb7-9" > < a href = "#cb7-9" > < / a > < / span >
< span id = "cb7-10" > < a href = "#cb7-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 = "cb7-11" > < a href = "#cb7-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 = "cb7-12" > < a href = "#cb7-12" > < / a > stat < 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 >
< span id = "cb7-13" > < a href = "#cb7-13" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > stat< span class = "op" > )< / span > < / span >
< span id = "cb7-14" > < a href = "#cb7-14" > < / a > gtk_text_buffer_set_modified < span class = "op" > (< / span > tb< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb7-15" > < a href = "#cb7-15" > < / a > < span class = "cf" > else< / span > < span class = "op" > {< / span > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb7-16" > < a href = "#cb7-16" > < / a > alert_dialog < span class = "op" > =< / span > gtk_alert_dialog_new < span class = "op" > (< / span > < span class = "st" > " %s" < / span > < span class = "op" > ,< / span > err< span class = "op" > -> < / span > message< span class = "op" > );< / span > < / span >
< span id = "cb7-17" > < a href = "#cb7-17" > < / a > gtk_alert_dialog_show < span class = "op" > (< / span > alert_dialog< span class = "op" > ,< / span > win< span class = "op" > );< / span > < / span >
< span id = "cb7-18" > < a href = "#cb7-18" > < / a > g_object_unref < span class = "op" > (< / span > alert_dialog< span class = "op" > );< / span > < / span >
< span id = "cb7-19" > < a href = "#cb7-19" > < / a > g_error_free < span class = "op" > (< / span > err< span class = "op" > );< / span > < / span >
< span id = "cb7-20" > < a href = "#cb7-20" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb7-21" > < a href = "#cb7-21" > < / a > g_free < span class = "op" > (< / span > contents< span class = "op" > );< / span > < / span >
< span id = "cb7-22" > < a href = "#cb7-22" > < / a > < span class = "cf" > return< / span > stat< span class = "op" > ;< / span > < / span >
< span id = "cb7-23" > < a href = "#cb7-23" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-04-17 13:54:42 +02:00
< ul >
2022-12-21 14:31:33 +01:00
< li > The function < code > save_file< / code > is called from
2022-11-21 14:48:20 +01:00
< 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
2022-12-21 14:31:33 +01:00
argument. If error happens, it displays an error message. So, a caller
of this function don’ t need to take care of errors. The class of this
function is < code > static< / code > . Therefore, only functions in this file
(< code > tfetextview.c< / code > ) call this function. Such static functions
2023-07-15 10:27:53 +02:00
usually don’ t have < code > g_return_val_if_fail< / code > functions.< / li >
2022-04-17 13:54:42 +02:00
< li > 10-11: Gets the text contents from the buffer.< / li >
2022-12-21 14:31:33 +01:00
< li > 12: The function < code > g_file_replace_contents< / code > writes the
contents to the file and returns the status (true = success/ false =
fail). It has many parameters, but some of them are almost always given
the same values.
< ul >
< li > GFile* file: GFile to which the contents are saved.< / li >
< li > const char* contents: contents to be saved. The string is owned by
the caller.< / li >
< li > gsize length: the length of the contents< / li >
< li > const char* etag: entity tag. It is usually NULL.< / li >
< li > gboolean make_backup: true to make a backup if the file exists.
false not to make it. the file will be overwritten.< / li >
< li > GFileCreateFlags flags: usually < code > G_FILE_CREATE_NONE< / code > is
fine.< / li >
< li > char** new_etag: new entity tag. It is usually NULL.< / li >
< li > GCancellable* cancellable: If a cancellable instance is set, the
other thread can cancel this operation. it is usually NULL.< / li >
< li > GError** error: If error happens, GError will be set.< / li >
< / ul > < / li >
< li > 13,14: If no error happens, set the modified flag to be FALSE. This
means that the buffer is not modified since it has been saved.< / li >
2023-07-15 10:27:53 +02:00
< li > 16-19: If it fails to save the contents, an error message will be
2022-12-21 14:31:33 +01:00
displayed.< / li >
2023-07-15 10:27:53 +02:00
< li > 16: Creates an alert dialog. The parameters are printf-like format
string followed by values to insert into the string. GtkAlertDialog is
available since version 4.10. If your version is older than 4.10, use
GtkMessageDialog instead. GtkMessageDialog is deprecated since version
4.10.< / li >
< li > 17: Show the alert dialog. The parameters are the dialog and the
transient parent window. 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 by giving
NULL as the argument. However, it is encouraged to give parents to
2022-12-21 14:31:33 +01:00
dialogs.< / li >
2023-07-15 10:27:53 +02:00
< li > 18: Releases the dialog.< / li >
< li > 19: Frees the GError struct pointed by < code > err< / code > with
< code > g_error_free< / code > function.< / li >
< li > 21: Frees < code > contents< / code > .< / li >
< li > 22: Returns the status to the caller.< / li >
2022-12-21 14:31:33 +01:00
< / ul >
2023-07-15 10:27:53 +02:00
< h3 id = "save_dialog_cb-function" > save_dialog_cb function< / h3 >
2022-12-21 14:31:33 +01:00
< 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 > < span class = "dt" > void< / span > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb8-2" > < a href = "#cb8-2" > < / a > save_dialog_cb< span class = "op" > (< / span > GObject < span class = "op" > *< / span > source_object< span class = "op" > ,< / span > GAsyncResult < span class = "op" > *< / span > res< span class = "op" > ,< / span > gpointer data< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-3" > < a href = "#cb8-3" > < / a > GtkFileDialog < span class = "op" > *< / span > dialog < span class = "op" > =< / span > GTK_FILE_DIALOG < span class = "op" > (< / span > source_object< span class = "op" > );< / span > < / span >
< span id = "cb8-4" > < a href = "#cb8-4" > < / a > TfeTextView < span class = "op" > *< / span > tv < span class = "op" > =< / span > TFE_TEXT_VIEW < span class = "op" > (< / span > data< span class = "op" > );< / span > < / span >
< span id = "cb8-5" > < a href = "#cb8-5" > < / 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-6" > < a href = "#cb8-6" > < / a > GFile < span class = "op" > *< / span > file< span class = "op" > ;< / span > < / span >
< span id = "cb8-7" > < a href = "#cb8-7" > < / 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 >
< 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 >
< span id = "cb8-9" > < a href = "#cb8-9" > < / a > GtkAlertDialog < span class = "op" > *< / span > alert_dialog< span class = "op" > ;< / span > < / span >
< span id = "cb8-10" > < a href = "#cb8-10" > < / a > < / span >
< span id = "cb8-11" > < a href = "#cb8-11" > < / a > < span class = "cf" > if< / span > < span class = "op" > (((< / span > file < span class = "op" > =< / span > gtk_file_dialog_save_finish < span class = "op" > (< / span > dialog< span class = "op" > ,< / span > res< span class = "op" > ,< / span > < span class = "op" > & < / span > err< span class = "op" > ))< / span > < span class = "op" > !=< / span > NULL< span class = "op" > )< / 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-12" > < a href = "#cb8-12" > < / a > < span class = "co" > // The following is complicated. The comments here will help your understanding< / span > < / span >
< span id = "cb8-13" > < a href = "#cb8-13" > < / a > < span class = "co" > // G_IS_FILE(tv-> file) & & tv-> file == file => nothing to do< / span > < / span >
< span id = "cb8-14" > < a href = "#cb8-14" > < / a > < span class = "co" > // G_IS_FILE(tv-> file) & & tv-> file != file => unref(tv-> file), tv-> file=file, emit change_file signal< / span > < / span >
< span id = "cb8-15" > < a href = "#cb8-15" > < / a > < span class = "co" > // tv-> file==NULL => tv-> file=file, emit change_file signal< / span > < / span >
< span id = "cb8-16" > < a href = "#cb8-16" > < / a > < span class = "cf" > if< / span > < span class = "op" > (!< / span > < span class = "op" > (< / span > G_IS_FILE < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > )< / span > < span class = "op" > & & < / span > g_file_equal < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ,< / span > file< span class = "op" > )))< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-17" > < a href = "#cb8-17" > < / 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-18" > < a href = "#cb8-18" > < / a > g_object_unref < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > );< / span > < / span >
< span id = "cb8-19" > < a href = "#cb8-19" > < / a > tv< span class = "op" > -> < / span > file < span class = "op" > =< / span > file< span class = "op" > ;< / span > < span class = "co" > // The ownership of ' file' moves to TfeTextView.< / span > < / span >
< span id = "cb8-20" > < a href = "#cb8-20" > < / 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-21" > < a href = "#cb8-21" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb8-22" > < a href = "#cb8-22" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb8-23" > < a href = "#cb8-23" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > err< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb8-24" > < a href = "#cb8-24" > < / a > alert_dialog < span class = "op" > =< / span > gtk_alert_dialog_new < span class = "op" > (< / span > < span class = "st" > " %s" < / span > < span class = "op" > ,< / span > err< span class = "op" > -> < / span > message< span class = "op" > );< / span > < / span >
< span id = "cb8-25" > < a href = "#cb8-25" > < / a > gtk_alert_dialog_show < span class = "op" > (< / span > alert_dialog< span class = "op" > ,< / span > GTK_WINDOW < span class = "op" > (< / span > win< span class = "op" > ));< / span > < / span >
< span id = "cb8-26" > < a href = "#cb8-26" > < / a > g_object_unref < span class = "op" > (< / span > alert_dialog< span class = "op" > );< / span > < / span >
< span id = "cb8-27" > < a href = "#cb8-27" > < / a > g_clear_error < span class = "op" > (& < / span > err< span class = "op" > );< / span > < / span >
< span id = "cb8-28" > < a href = "#cb8-28" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb8-29" > < a href = "#cb8-29" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > The function < code > save_dialog_cb< / code > is a call back function
that is given to the < code > gtk_file_dialog_save< / code > function as an
argument. The < code > gtk_file_dialog_save< / code > shows a file chooser
dialog to the user. The user chooses or types a filename and clicks on
the < code > Save< / code > button or just clicks on the < code > Cancel< / code >
button. Then the call back function is called with the result. This is
the general way in GIO to manage asynchronous operations. A pair of
functions < code > g_data_input_stream_read_line_async< / code > and
< code > g_data_input_stream_read_line_finish< / code > are one example. These
functions are thread-safe. The arguments of < code > save_dialog_cb< / code >
are:
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > GObject *source_object: The GObject instance that the operation was
started with. It is actually the GtkFileDialog instance that is shown to
the user. However, the call back function is defined as
< code > AsyncReadyCallback< / code > , which is a general call back function
for an asynchronous operation. So the type is GObject and you need to
cast it to GtkFileDialog later.< / li >
< li > GAsyncResult *res: The result of the asynchronous operation. It will
be given to the < code > gtk_dialog_save_finish< / code > function.< / li >
< li > gpointer data: A user data set in the < code > gtk_dialog_save< / code >
function.< / li >
2022-12-21 14:31:33 +01:00
< / ul > < / li >
2023-07-15 10:27:53 +02:00
< li > 11: Calls < code > gtk_dialog_save_finish< / code > . It is given the
result < code > res< / code > as an argument and returns a pointer to a GFile
object the user has chosen. If the user has canceled or an error
happens, it returns NULL, creates a GError object and sets
< code > err< / code > to point it. If < code > gtk_dialog_save_finish< / code >
returns a GFile, the function < code > save_file< / code > is called.< / li >
< li > 12-21: If the file is successfully saved, these lines are executed.
See the comments, line 12-15, for the details.< / li >
< li > 23-28: If an error happens, show the error message through the alert
dialog.< / li >
2022-12-21 14:31:33 +01:00
< / ul >
< h3 id = "tfe_text_view_save-function" > tfe_text_view_save function< / h3 >
< div class = "sourceCode" id = "cb9" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb9-1" > < a href = "#cb9-1" > < / a > < span class = "dt" > void< / span > < / span >
< span id = "cb9-2" > < a href = "#cb9-2" > < / 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 = "cb9-3" > < a href = "#cb9-3" > < / 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 = "cb9-4" > < a href = "#cb9-4" > < / a > < / span >
< span id = "cb9-5" > < a href = "#cb9-5" > < / 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 = "cb9-6" > < a href = "#cb9-6" > < / 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 >
< span id = "cb9-7" > < a href = "#cb9-7" > < / a > < / span >
< span id = "cb9-8" > < a href = "#cb9-8" > < / 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 = "cb9-9" > < a href = "#cb9-9" > < / a > < span class = "cf" > return< / span > < span class = "op" > ;< / span > < span class = "co" > /* no need to save it */< / span > < / span >
< span id = "cb9-10" > < a href = "#cb9-10" > < / 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 = "cb9-11" > < a href = "#cb9-11" > < / a > tfe_text_view_saveas < span class = "op" > (< / span > tv< span class = "op" > );< / span > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb9-12" > < a href = "#cb9-12" > < / a > < span class = "cf" > else< / span > < / span >
< span id = "cb9-13" > < a href = "#cb9-13" > < / 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 = "cb9-14" > < a href = "#cb9-14" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-12-21 14:31:33 +01:00
< ul >
< li > The function < code > tfe_text_view_save< / code > writes the contents to
the < code > tv-> file< / code > file. It calls
< code > tfe_text_view_saveas< / code > or < code > save_file< / code > .< / li >
< li > 1-3: The function is public, i.e. it is open to the other objects.
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
2022-11-21 14:48:20 +01:00
< code > g_return_val_if_fail< / code > , but no value is returned because
2022-12-21 14:31:33 +01:00
< code > tfe_text_view_save< / code > doesn’ t return a value (void).< / li >
< li > 5-6: GtkTextBuffer < code > tb< / code > and GtkWidget (GtkWindow)
< code > win< / code > are set. The function
< code > gtk_widget_get_ancestor (widget, type)< / code > returns the first
2023-07-15 10:27:53 +02:00
ancestor of the widget with the type, which is a GType. The parent-child
relationship here is the one for widgets, not classes. More precisely,
the returned widget’ s type is the < code > type< / code > or a descendant
object type of the < code > type< / code > . Be careful, the “descendant
object” in the previous sentence is < em > not< / em > “descendant widget”.
For example, the type of GtkWindow is < code > GTK_TYPE_WINDOW< / code > and
the one of TfeTextView is < code > TFE_TYPE_TEXT_VIEW< / code > . The top level
window may be a GtkApplicationWindow, but it is a descendant of
GtkWindow. Therefore,
< code > gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW)< / code >
possibly returns GtkWindow or GtkApplicationWindow.< / li >
2022-12-21 14:31:33 +01:00
< li > 8-9: If the buffer hasn’ t modified, it doesn’ t need to be
saved.< / li >
< li > 10-11: If < code > tv-> file< / code > is NULL, which means no file has
given yet, it calls < code > tfe_text_view_saveas< / code > to prompt a user
to select a file and save the contents.< / li >
2023-07-15 10:27:53 +02:00
< li > 12-13: Otherwise, it calls < code > save_file< / code > to save the
2022-12-21 14:31:33 +01:00
contents to the file < code > tv-> file< / code > .< / li >
< / ul >
< h3 id = "tfe_text_view_saveas-function" > tfe_text_view_saveas
function< / h3 >
< 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" > void< / span > < / span >
< span id = "cb10-2" > < a href = "#cb10-2" > < / 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 = "cb10-3" > < a href = "#cb10-3" > < / 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-4" > < a href = "#cb10-4" > < / a > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb10-5" > < a href = "#cb10-5" > < / 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 >
< span id = "cb10-6" > < a href = "#cb10-6" > < / a > GtkFileDialog < span class = "op" > *< / span > dialog< span class = "op" > ;< / span > < / span >
2022-12-21 14:31:33 +01:00
< span id = "cb10-7" > < a href = "#cb10-7" > < / a > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb10-8" > < a href = "#cb10-8" > < / a > dialog < span class = "op" > =< / span > gtk_file_dialog_new < span class = "op" > ();< / span > < / span >
< span id = "cb10-9" > < a href = "#cb10-9" > < / a > gtk_file_dialog_save < span class = "op" > (< / span > dialog< span class = "op" > ,< / span > GTK_WINDOW < span class = "op" > (< / span > win< span class = "op" > ),< / span > NULL< span class = "op" > ,< / span > save_dialog_cb< span class = "op" > ,< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb10-10" > < a href = "#cb10-10" > < / a > g_object_unref < span class = "op" > (< / span > dialog< span class = "op" > );< / span > < / span >
< span id = "cb10-11" > < a href = "#cb10-11" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
< p > The function < code > tfe_text_view_saveas< / code > shows a file chooser
dialog and prompts the user to choose a file and save the contents.< / p >
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > 1-3: Check the type of < code > tv< / code > because the function is
public.< / li >
< li > 6: GtkWidget < code > win< / code > is set to the window which is an
ancestor ot < code > tv< / code > .< / li >
< li > 8: Creates a GtkFileDialog instance. GtkFileDialog is available
since version 4.10. If your Gtk version is older than 4.10, use
GtkFileChooserDialog instead. GtkFileChooserDialog is deprecated since
version 4.10.< / li >
< li > 9: Calls < code > gtk_file_dialog_save< / code > function. The arguments
are:
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > dialog: GtkFileDialog.< / li >
< li > GTK_WINDOW (win): transient parent window.< / li >
< li > NULL: NULL means no cancellable object. If you put a cancellable
object here, you can cancel the operation by other thread. In many
cases, it is NULL. See < a
href="https://docs.gtk.org/gio/class.Cancellable.html">GCancellable< / a >
for further information.< / li >
< li > < code > save_dialog_cb< / code > : A callback to call when the operation
is complete. The type of the pointer to the callback function is < a
href="https://docs.gtk.org/gio/callback.AsyncReadyCallback.html">GAsyncReadyCallback< / a > .
If a cancellable object is given and the operation is cancelled, the
callback won’ t be called.< / li >
< li > < code > tv< / code > : This is an optional user data which is gpointer
type. It is used in the callback function.< / li >
2022-12-21 14:31:33 +01:00
< / ul > < / li >
2023-07-15 10:27:53 +02:00
< li > 10: Releases the GtkFileDialog instance because it is useless
anymore.< / li >
2022-04-17 13:54:42 +02:00
< / ul >
2023-07-15 10:27:53 +02:00
< p > This function just shows the file chooser dialog. The rest of the
operation is done by the callback function.< / p >
2022-12-21 14:31:33 +01:00
< figure >
< img src = "image/saveas.png" alt = "Saveas process" / >
< figcaption aria-hidden = "true" > Saveas process< / figcaption >
< / figure >
< h2 id = "open-related-functions" > Open related functions< / h2 >
2023-07-15 10:27:53 +02:00
< p > Open function shows a file chooser dialog to a user and prompts them
2022-12-21 14:31:33 +01:00
to choose a file. Then it reads the file and puts the text into
2022-11-21 14:48:20 +01:00
GtkTextBuffer.< / p >
2022-12-21 14:31:33 +01:00
< div class = "sourceCode" id = "cb11" > < pre class = "sourceCode c" > < code class = "sourceCode c" > < span id = "cb11-1" > < a href = "#cb11-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 >
2023-07-15 10:27:53 +02:00
< p > The parameter < code > win< / code > is the transient window. A file
chooser dialog will be shown at the center of the window.< / p >
2022-12-21 14:31:33 +01:00
< p > This function may 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 >
2022-11-21 14:48:20 +01:00
< 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
2022-12-21 14:31:33 +01:00
want to revert the buffer, calling this function is appropriate.< / p >
2023-07-15 10:27:53 +02:00
< p > Open and read process is divided into two phases. One is creating and
showing a file chooser dialog and the other is the callback function.
The former is < code > tfe_text_view_open< / code > and the latter is
< code > open_dialog_cb< / code > .< / p >
< h3 id = "open_dialog_cb-function" > open_dialog_cb function< / h3 >
2022-12-21 14:31:33 +01:00
< div class = "sourceCode" id = "cb12" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb12-1" > < a href = "#cb12-1" > < / a > < span class = "dt" > static< / span > < span class = "dt" > void< / span > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb12-2" > < a href = "#cb12-2" > < / a > open_dialog_cb < span class = "op" > (< / span > GObject < span class = "op" > *< / span > source_object< span class = "op" > ,< / span > GAsyncResult < span class = "op" > *< / span > res< span class = "op" > ,< / span > gpointer data< span class = "op" > )< / span > < span class = "op" > {< / span > < / span >
< span id = "cb12-3" > < a href = "#cb12-3" > < / a > GtkFileDialog < span class = "op" > *< / span > dialog < span class = "op" > =< / span > GTK_FILE_DIALOG < span class = "op" > (< / span > source_object< span class = "op" > );< / span > < / span >
< span id = "cb12-4" > < a href = "#cb12-4" > < / a > TfeTextView < span class = "op" > *< / span > tv < span class = "op" > =< / span > TFE_TEXT_VIEW < span class = "op" > (< / span > data< span class = "op" > );< / span > < / span >
< span id = "cb12-5" > < a href = "#cb12-5" > < / 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 = "cb12-6" > < a href = "#cb12-6" > < / 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 >
< span id = "cb12-7" > < a href = "#cb12-7" > < / a > GFile < span class = "op" > *< / span > file< span class = "op" > ;< / span > < / span >
< span id = "cb12-8" > < a href = "#cb12-8" > < / a > < span class = "dt" > char< / span > < span class = "op" > *< / span > contents< span class = "op" > ;< / span > < / span >
< span id = "cb12-9" > < a href = "#cb12-9" > < / a > gsize length< span class = "op" > ;< / span > < / span >
< span id = "cb12-10" > < a href = "#cb12-10" > < / a > gboolean file_changed< span class = "op" > ;< / span > < / span >
< span id = "cb12-11" > < a href = "#cb12-11" > < / a > GtkAlertDialog < span class = "op" > *< / span > alert_dialog< span class = "op" > ;< / span > < / span >
< span id = "cb12-12" > < a href = "#cb12-12" > < / a > GError < span class = "op" > *< / span > err < span class = "op" > =< / span > NULL< span class = "op" > ;< / span > < / span >
< span id = "cb12-13" > < a href = "#cb12-13" > < / a > < / span >
< span id = "cb12-14" > < a href = "#cb12-14" > < / a > < span class = "cf" > if< / span > < span class = "op" > ((< / span > file < span class = "op" > =< / span > gtk_file_dialog_open_finish < span class = "op" > (< / span > dialog< span class = "op" > ,< / span > res< span class = "op" > ,< / span > < span class = "op" > & < / span > err< span class = "op" > ))< / span > < span class = "op" > !=< / span > NULL< / span >
< span id = "cb12-15" > < a href = "#cb12-15" > < / a > < 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 >
< span id = "cb12-16" > < a href = "#cb12-16" > < / 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 = "cb12-17" > < a href = "#cb12-17" > < / a > g_free < span class = "op" > (< / span > contents< span class = "op" > );< / span > < / span >
< span id = "cb12-18" > < a href = "#cb12-18" > < / a > gtk_text_buffer_set_modified < span class = "op" > (< / span > tb< span class = "op" > ,< / span > FALSE< span class = "op" > );< / span > < / span >
< span id = "cb12-19" > < a href = "#cb12-19" > < / a > < span class = "co" > // G_IS_FILE(tv-> file) & & tv-> file == file => unref(tv-> file), tv-> file=file, emit response with SUCCESS< / span > < / span >
< span id = "cb12-20" > < a href = "#cb12-20" > < / a > < span class = "co" > // G_IS_FILE(tv-> file) & & tv-> file != file => unref(tv-> file), tv-> file=file, emit response with SUCCESS, emit change-file< / span > < / span >
< span id = "cb12-21" > < a href = "#cb12-21" > < / a > < span class = "co" > // tv-> file==NULL => tv-> file=file, emit response with SUCCESS, emit change-file< / span > < / span >
< span id = "cb12-22" > < a href = "#cb12-22" > < / a > < span class = "co" > // The order is important. If you unref tv-> file first, you can' t compare tv-> file and file anymore.< / span > < / span >
< span id = "cb12-23" > < a href = "#cb12-23" > < / a > < span class = "co" > // And the signals are emitted after new tv-> file is set. Or the handler can' t catch the new file.< / span > < / span >
< span id = "cb12-24" > < a href = "#cb12-24" > < / a > file_changed < span class = "op" > =< / span > < span class = "op" > (< / span > G_IS_FILE < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > )< / span > < span class = "op" > & & < / span > g_file_equal < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > ,< / span > file< span class = "op" > ))< / span > < span class = "op" > ?< / span > FALSE < span class = "op" > :< / span > TRUE< span class = "op" > ;< / span > < / span >
< span id = "cb12-25" > < a href = "#cb12-25" > < / 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 = "cb12-26" > < a href = "#cb12-26" > < / a > g_object_unref < span class = "op" > (< / span > tv< span class = "op" > -> < / span > file< span class = "op" > );< / span > < / span >
< span id = "cb12-27" > < a href = "#cb12-27" > < / a > tv< span class = "op" > -> < / span > file < span class = "op" > =< / span > file< span class = "op" > ;< / span > < span class = "co" > // The ownership of ' file' moves to TfeTextView< / span > < / span >
< span id = "cb12-28" > < a href = "#cb12-28" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > file_changed< span class = "op" > )< / span > < / span >
< span id = "cb12-29" > < a href = "#cb12-29" > < / 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 = "cb12-30" > < a href = "#cb12-30" > < / 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 = "cb12-31" > < a href = "#cb12-31" > < / a > < span class = "op" > }< / span > < span class = "cf" > else< / span > < span class = "op" > {< / span > < / span >
< span id = "cb12-32" > < a href = "#cb12-32" > < / a > < span class = "cf" > if< / span > < span class = "op" > (< / span > err< span class = "op" > -> < / span > code < span class = "op" > ==< / span > GTK_DIALOG_ERROR_DISMISSED< span class = "op" > )< / span > < span class = "co" > // The user canceled the file chooser dialog< / span > < / span >
< span id = "cb12-33" > < a href = "#cb12-33" > < / 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 = "cb12-34" > < a href = "#cb12-34" > < / a > < span class = "cf" > else< / span > < span class = "op" > {< / span > < / span >
< span id = "cb12-35" > < a href = "#cb12-35" > < / a > alert_dialog < span class = "op" > =< / span > gtk_alert_dialog_new < span class = "op" > (< / span > < span class = "st" > " %s" < / span > < span class = "op" > ,< / span > err< span class = "op" > -> < / span > message< span class = "op" > );< / span > < / span >
< span id = "cb12-36" > < a href = "#cb12-36" > < / a > gtk_alert_dialog_show < span class = "op" > (< / span > alert_dialog< span class = "op" > ,< / span > GTK_WINDOW < span class = "op" > (< / span > win< span class = "op" > ));< / span > < / span >
< span id = "cb12-37" > < a href = "#cb12-37" > < / a > g_object_unref < span class = "op" > (< / span > alert_dialog< span class = "op" > );< / span > < / span >
< span id = "cb12-38" > < a href = "#cb12-38" > < / 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 = "cb12-39" > < a href = "#cb12-39" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb12-40" > < a href = "#cb12-40" > < / a > g_clear_error < span class = "op" > (& < / span > err< span class = "op" > );< / span > < / span >
< span id = "cb12-41" > < a href = "#cb12-41" > < / a > < span class = "op" > }< / span > < / span >
< span id = "cb12-42" > < a href = "#cb12-42" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
< p > This function is similar to < code > save_dialog_cb< / code > . Both are
callback functions on a GtkFileDialog object.< / p >
2022-04-17 13:54:42 +02:00
< ul >
2023-07-15 10:27:53 +02:00
< li > 2: It has three parameters like < code > save_dialog_cb< / code > . They
are:
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > GObject *source_object: The GObject instance that the operation was
started with. It is actually the GtkFileDialog instance that is shown to
the user. It will be casted to GtkFileDialog later.< / li >
< li > GAsyncResult *res: The result of the asynchronous operation. It will
be given to the < code > gtk_dialog_open_finish< / code > function.< / li >
< li > gpointer data: A user data set in the < code > gtk_dialog_open< / code >
function. It is actually a TfeTextView instance and it will be casted to
TfeTextView later.< / li >
2022-12-21 14:31:33 +01:00
< / ul > < / li >
2023-07-15 10:27:53 +02:00
< li > 14: The function < code > gtk_file_dialog_open_finish< / code > returns a
GFile object if the operation has succeeded. Otherwise it returns
NULL.< / li >
< li > 16-30: If the user selects a file and the file has successfully been
read, the codes from 16 to 30 will be executed.< / li >
< li > 16-18: Sets the buffer of < code > tv< / code > with the text read from
the file. And frees < code > contents< / code > . Then sets the modified status
to false.< / li >
< li > 19-30: The codes are a bit complicated. See the comments. If the
file (< code > tv-> file< / code > ) is changed, “change-file” signal is
emitted. The signal “open-response” is emitted with the parameter
< code > TFE_OPEN_RESPONSE_SUCCESS< / code > .< / li >
< li > 31-41: If the operation failed, the codes from 31 to 41 will be
executed.< / li >
< li > 32-33: If the error code is < code > GTK_DIALOG_ERROR_DISMISSED< / code > ,
it means that the user has clicked on the “Cancel” button or close
button on the header bar. Then, “open-response” signal is emitted with
the parameter < code > TFE_OPEN_RESPONSE_CANCEL< / code > . The Dialog error is
described < a
href="https://docs.gtk.org/gtk4/error.DialogError.html">here< / a > in the
GTK API reference.< / li >
< li > 35-38: If another error occurs, it shows an alert dialog to report
the error and emits “open-response” signal with the parameter
2022-11-21 14:48:20 +01:00
< code > TFE_OPEN_RESPONSE_ERROR< / code > .< / li >
2023-07-15 10:27:53 +02:00
< li > 40: Clears the error structure.< / li >
2022-12-21 14:31:33 +01:00
< / ul >
< h3 id = "tfe_text_view_open-function" > tfe_text_view_open function< / h3 >
< div class = "sourceCode" id = "cb13" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb13-1" > < a href = "#cb13-1" > < / a > < span class = "dt" > void< / span > < / span >
< span id = "cb13-2" > < a href = "#cb13-2" > < / 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 = "cb13-3" > < a href = "#cb13-3" > < / a > g_return_if_fail < span class = "op" > (< / span > TFE_IS_TEXT_VIEW < span class = "op" > (< / span > tv< span class = "op" > ));< / span > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb13-4" > < a href = "#cb13-4" > < / a > < span class = "co" > // ' win' is used for a transient window of the GtkFileDialog.< / span > < / span >
2022-12-21 14:31:33 +01:00
< span id = "cb13-5" > < a href = "#cb13-5" > < / a > < span class = "co" > // It can be NULL.< / span > < / span >
< span id = "cb13-6" > < a href = "#cb13-6" > < / a > g_return_if_fail < span class = "op" > (< / span > GTK_IS_WINDOW < span class = "op" > (< / span > win< span class = "op" > )< / span > < span class = "op" > ||< / span > win < span class = "op" > ==< / span > NULL< span class = "op" > );< / span > < / span >
< span id = "cb13-7" > < a href = "#cb13-7" > < / a > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb13-8" > < a href = "#cb13-8" > < / a > GtkFileDialog < span class = "op" > *< / span > dialog< span class = "op" > ;< / span > < / span >
2022-12-21 14:31:33 +01:00
< span id = "cb13-9" > < a href = "#cb13-9" > < / a > < / span >
2023-07-15 10:27:53 +02:00
< span id = "cb13-10" > < a href = "#cb13-10" > < / a > dialog < span class = "op" > =< / span > gtk_file_dialog_new < span class = "op" > ();< / span > < / span >
< span id = "cb13-11" > < a href = "#cb13-11" > < / a > gtk_file_dialog_open < span class = "op" > (< / span > dialog< span class = "op" > ,< / span > win< span class = "op" > ,< / span > NULL< span class = "op" > ,< / span > open_dialog_cb< span class = "op" > ,< / span > tv< span class = "op" > );< / span > < / span >
< span id = "cb13-12" > < a href = "#cb13-12" > < / a > g_object_unref < span class = "op" > (< / span > dialog< span class = "op" > );< / span > < / span >
< span id = "cb13-13" > < a href = "#cb13-13" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > 3-6: Check the type of the arguments < code > tv< / code > and
2022-12-21 14:31:33 +01:00
< code > win< / code > . Public functions always need to check the
arguments.< / li >
2023-07-15 10:27:53 +02:00
< li > 10: Creates a GtkFileDialog instance.< / li >
< li > 11: Calls < code > gtk_file_dialog_open< / code > . The arguments are:
2022-12-21 14:31:33 +01:00
< ul >
2023-07-15 10:27:53 +02:00
< li > < code > dialog< / code > : the GtkFileDialog instance< / li >
< li > < code > win< / code > : the transient window for the file chooser
dialog< / li >
< li > < code > NULL< / code > : NULL means no cancellable object< / li >
< li > < code > open_dialog_cb< / code > : callback function< / li >
< li > < code > tv< / code > : user data which is used in the callback
function< / li >
2022-12-21 14:31:33 +01:00
< / ul > < / li >
2023-07-15 10:27:53 +02:00
< li > 12: Releases the dialog instance because it is useless anymore.< / li >
2022-04-17 13:54:42 +02:00
< / ul >
2022-12-21 14:31:33 +01:00
< p > The whole process between the caller and TfeTextView is shown in the
2023-07-15 10:27:53 +02:00
following diagram. It is really complicated. Because
< code > gtk_file_dialog_open< / code > can’ t return the status of the
operation.< / 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
2023-07-15 10:27:53 +02:00
select a file from the file chooser dialog.< / li >
< li > When the dialog is closed, the callback < code > open_dialog_cb< / code >
is called.< / li >
< li > The callback function reads the file and inserts the text into
GtkTextBuffer and emits a signal to inform the status as a response
code.< / li >
< li > The handler of the “open-response” signal is invoked and the
operation status is given to it as an argument (signal parameter).< / li >
2022-04-17 13:54:42 +02:00
< / ol >
2022-12-21 14:31:33 +01:00
< h2 id = "getting-gfile-in-tfetextview" > Getting GFile in TfeTextView< / h2 >
< p > You can get the GFile in a TfeTextView instance with
< code > tfe_text_view_get_file< / code > . It is very simple.< / p >
< div class = "sourceCode" id = "cb14" > < pre
class="sourceCode numberSource C numberLines">< code class = "sourceCode c" > < span id = "cb14-1" > < a href = "#cb14-1" > < / a > GFile < span class = "op" > *< / span > < / span >
< span id = "cb14-2" > < a href = "#cb14-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 = "cb14-3" > < a href = "#cb14-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 >
< span id = "cb14-4" > < a href = "#cb14-4" > < / a > < / span >
< span id = "cb14-5" > < a href = "#cb14-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 = "cb14-6" > < a href = "#cb14-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 >
< span id = "cb14-7" > < a href = "#cb14-7" > < / a > < span class = "cf" > else< / span > < / span >
< span id = "cb14-8" > < a href = "#cb14-8" > < / a > < span class = "cf" > return< / span > NULL< span class = "op" > ;< / span > < / span >
< span id = "cb14-9" > < a href = "#cb14-9" > < / a > < span class = "op" > }< / span > < / span > < / code > < / pre > < / div >
2022-11-21 14:48:20 +01:00
< 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
2022-12-21 14:31:33 +01:00
href="https://docs.gtk.org/gio/method.File.dup.html">Gio API Reference –
2022-11-21 14:48:20 +01:00
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 >
2022-12-21 14:31:33 +01:00
< p > Refer < a
href="https://toshiocp.github.io/Gtk4-tutorial/tfetextview_doc.html">API
document of TfeTextView< / a > . The markdown file is under the directory
< code > src/tfetextview< / code > .< / p >
< p > You can find all the TfeTextView source codes under src/tfetextview
2022-11-21 14:48:20 +01:00
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 >