Functions in GtkNotebook
GtkNotebook is a very important object in the text file
editor tfe. It connects the application and
TfeTextView objects. A set of public functions are declared in
tfenotebook.h. The name “tfenotebook” is used only
for filenames; no “TfeNotebook” object type is defined. There’s
no “TfeNotebook” object.
The source files are in the directory src/tfe5.
You can get them by downloading the repository.
void
notebook_page_save(GtkNotebook *nb);
void
notebook_page_close (GtkNotebook *nb);
void
notebook_page_open (GtkNotebook *nb);
void
notebook_page_new_with_file (GtkNotebook *nb, GFile *file);
void
notebook_page_new (GtkNotebook *nb);This header file describes the public functions in
tfenotebook.c.
- 1-2:
notebook_page_savesaves the current page to the file with the name specified in the tab.” If the name isuntitledoruntitledfollowed by digits, a file chooser dialog appears and a user can choose or specify a filename. - 4-5:
notebook_page_closecloses the current page. - 7-8:
notebook_page_openshows a file chooser dialog and a user can choose a file. The contents of the file is inserted to a new page. - 10-11:
notebook_page_new_with_filecreates a new page and a file given as an argument is read and inserted into the page. - 13-14:
notebook_page_newcreates a new empty page.
You probably find that the functions except
notebook_page_close are higher level functions
of
tfe_text_view_savetef_text_view_opentfe_text_view_new_with_filetfe_text_view_new
respectively.
There are two layers. One of them is
tfe_text_view ..., which is the lower level layer.
The other is notebook ..., which is the higher
level layer.
Now let’s look at the program of each function.
notebook_page_new
static char *
get_untitled () {
static int c = -1;
if (++c == 0)
return g_strdup_printf("Untitled");
else
return g_strdup_printf ("Untitled%u", c);
}
static void
notebook_page_build (GtkNotebook *nb, GtkWidget *tv, const char *filename) {
GtkWidget *scr = gtk_scrolled_window_new ();
GtkNotebookPage *nbp;
GtkWidget *lab;
int i;
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
lab = gtk_label_new (filename);
i = gtk_notebook_append_page (nb, scr, lab);
nbp = gtk_notebook_get_page (nb, scr);
g_object_set (nbp, "tab-expand", TRUE, NULL);
gtk_notebook_set_current_page (nb, i);
g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed_cb), nb);
}
void
notebook_page_new (GtkNotebook *nb) {
g_return_if_fail(GTK_IS_NOTEBOOK (nb));
GtkWidget *tv;
char *filename;
tv = tfe_text_view_new ();
filename = get_untitled ();
notebook_page_build (nb, tv, filename);
g_free (filename);
}- 26-37: The function
notebook_page_new. - 28: The function
g_return_if_failchecks the argument. It’s necessary because the function is public. - 33: Creates TfeTextView object.
- 34: Creates filename, which is “Untitled”, “Untitled1”, … .
- 1-8: The function
get_untitled. - 3: Static variable
cis initialized at the first call of this function. After thatckeeps its value unless it is changed explicitly. - 4-7: Increases
cby one and if it is zero, it returns “Untitled”. If it is a positive integer, it returns “Untitled<the integer>”, for example, “Untitled1”, “Untitled2”, and so on. The functiong_strdup_printfcreates a string and it should be freed byg_freewhen it becomes useless. The caller ofget_untitledis in charge of freeing the string. - 36: Calls
notebook_page_buildto build a new page. - 37: Frees
filename. - 10- 24: The function
notebook_page_build. A parameter with theconstqualifier cannot be modified within the function. It means that the argumentfilenameis owned by the caller. The caller is responsible for freeing it when it is no longer needed. - 12: Creates GtkScrolledWindow.
- 17: Inserts
tvto GtkScrolledWindow as a child. - 18-19: Creates GtkLabel, then appends
scrandlabto the GtkNotebook instancenb. - 20-21: Sets “tab-expand” property to TRUE. The function
g_object_setsets properties on an object. The object can be any object derived from GObject. In many cases, an object has its own function to set its properties, but sometimes does not. In that case, useg_object_setto set the property. - 22: Sets the current page to the newly created page.
- 23: Connects “change-file” signal and the handler
file_changed_cb.
notebook_page_new_with_file
void
notebook_page_new_with_file (GtkNotebook *nb, GFile *file) {
g_return_if_fail(GTK_IS_NOTEBOOK (nb));
g_return_if_fail(G_IS_FILE (file));
GtkWidget *tv;
char *filename;
if ((tv = tfe_text_view_new_with_file (file)) == NULL)
return; /* read error */
filename = g_file_get_basename (file);
notebook_page_build (nb, tv, filename);
g_free (filename);
}- 9-10: Calls
tfe_text_view_new_with_file. If the function returns NULL, an error has happened. Then, it does nothing and returns. - 11-13: Gets the filename, builds a new page and frees
filename.
notebook_page_open
static void
open_response_cb (TfeTextView *tv, int response, GtkNotebook *nb) {
GFile *file;
char *filename;
if (response != TFE_OPEN_RESPONSE_SUCCESS) {
g_object_ref_sink (tv);
g_object_unref (tv);
}else {
file = tfe_text_view_get_file (tv);
filename = g_file_get_basename (file);
g_object_unref (file);
notebook_page_build (nb, GTK_WIDGET (tv), filename);
g_free (filename);
}
}
void
notebook_page_open (GtkNotebook *nb) {
g_return_if_fail(GTK_IS_NOTEBOOK (nb));
GtkWidget *tv;
tv = tfe_text_view_new ();
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response_cb), nb);
tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW)));
}- 18-27: The function
notebook_page_open. - 24: Creates TfeTextView object.
- 25: Connects the signal “open-response” and the handler
open_response_cb. - 26: Calls
tfe_text_view_open. The “open-response” signal will be emitted later in this function to inform the result. - 1-16: The handler
open_response_cb. - 6-8: If the response code is not
TFE_OPEN_RESPONSE_SUCCESS, the instancetvwill be destroyed. It has floating reference, which will be explained later. A floating reference needs to be converted into an ordinary reference before releasing it. The functiong_object_ref_sinkdoes that. After that, the functiong_object_unrefreleasestvand decreases the reference count by one. Finally the reference count becomes zero andtvis destroyed. - 9-15: Otherwise, it builds a new page with
tv.
Floating Reference
All the widgets are derived from GInitiallyUnowned. GObject and GInitiallyUnowned are almost the same. The difference is like this. When an instance of GInitiallyUnowned is created, the instance has a “floating reference”. On the other hand, when an instance of GObject (not GInitiallyUnowned) is created, it has “normal reference”. Their descendants inherits them, so every widget has a floating reference just after the creation. Non-widget class, for example, GtkTextBuffer is a direct sub class of GObject and it has normal reference.
The function g_object_ref_sink converts the
floating reference into a normal reference. If the instance does
not have a floating reference, g_object_ref_sink
simply increases the reference count by one. It is used when an
widget is added to another widget as a child.
GtkTextView *tv = gtk_text_view_new (); // Floating reference
GtkScrolledWindow *scr = gtk_scrolled_window_new ();
gtk_scrolled_window_set_child (scr, tv); // Scrolled window sinks the tv's floating reference and tv's reference count becomes one.
When tv is added to scr as a child,
g_object_ref_sink is used.
g_object_ref_sink (tv);
So, the floating reference is converted into an ordinary reference. That is to say, floating reference is removed, and the normal reference count is one. Thanks to this, the caller does not need to decrease tv’s reference count. If an Object_A were not a descendant of GInitiallyUnowned, the program would be like this:
Object_A *obj_a = object_a_new (); // reference count is one
GtkScrolledWindow *scr = gtk_scrolled_window_new ();
gtk_scrolled_window_set_child (scr, obj_a); // obj_a's reference count is two
// obj_a is referred by the caller (this program) and scrolled window
g_object_unref (obj_a); // obj_a's reference count is one because the caller no longer refers obj_a.
This example tells us that the caller needs to unref
obj_a.
If you use g_object_unref to an instance that
has a floating reference, you need to convert the floating
reference to a normal reference in advance. See GObject
API reference for further information.
notebook_page_close
void
notebook_page_close (GtkNotebook *nb) {
g_return_if_fail(GTK_IS_NOTEBOOK (nb));
GtkWidget *win;
int i;
if (gtk_notebook_get_n_pages (nb) == 1) {
win = gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW);
gtk_window_destroy(GTK_WINDOW (win));
} else {
i = gtk_notebook_get_current_page (nb);
gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
}
}This function closes the current page. If the page is the only page the notebook has, then the function destroys the top-level window and quits the application.
- 8-10: If the page is the only page the notebook has, it
calls
gtk_window_destroyto destroy the top-level window. - 11-13: Otherwise, removes the current page. The child widget (TfeTextView) is also destroyed.
notebook_page_save
static TfeTextView *
get_current_textview (GtkNotebook *nb) {
int i;
GtkWidget *scr;
GtkWidget *tv;
i = gtk_notebook_get_current_page (nb);
scr = gtk_notebook_get_nth_page (nb, i);
tv = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scr));
return TFE_TEXT_VIEW (tv);
}
void
notebook_page_save (GtkNotebook *nb) {
g_return_if_fail(GTK_IS_NOTEBOOK (nb));
TfeTextView *tv;
tv = get_current_textview (nb);
tfe_text_view_save (tv);
}- 13-21:
notebook_page_save. - 19: Gets the TfeTextView instance belongs to the current
page. The caller does not have the ownership of
tvso you don’t need to care about the reference count oftv. - 20: Calls
tfe_text_view_save. - 1-11:
get_current_textview. This function gets the TfeTextView object belongs to the current page. - 7: Gets the page number of the current page.
- 8: Gets the child widget
scr, which is a GtkScrolledWindow instance, of the current page. The objectscris owned by the notebooknb. - 9-10: Gets the child widget of
scr, which is a TfeTextView instance, and returns it. The returned instance is owned byscr.
file_changed_cb Handler
The function file_changed_cb is a handler
connected to “change-file” signal. If a file in a TfeTextView
instance is changed, the instance emits this signal. This
handler changes the label of the GtkNotebookPage.
static void
file_changed_cb (TfeTextView *tv, GtkNotebook *nb) {
GtkWidget *scr;
GtkWidget *label;
GFile *file;
char *filename;
file = tfe_text_view_get_file (tv);
scr = gtk_widget_get_parent (GTK_WIDGET (tv));
if (G_IS_FILE (file)) {
filename = g_file_get_basename (file);
g_object_unref (file);
} else
filename = get_untitled ();
label = gtk_label_new (filename);
g_free (filename);
gtk_notebook_set_tab_label (nb, scr, label);
}- 8: Gets the GFile instance from
tv. - 9: Gets the GkScrolledWindow instance which is the parent
widget of
tv. - 10-12: If
filepoints to a GFile instance, the filename of the GFile is assigned tofilename. Then, unref the GFile objectfile. - 13-14: Otherwise (file is NULL), a string
Untitled(number)is assigned tofilename. - 15-17: Creates a GtkLabel instance
labelwith the filename and set the label of the GtkNotebookPage withlabel.