Professional Documents
Culture Documents
GTK Development Using Glade 3
GTK Development Using Glade 3
Using Glade 3
GTK+ is a toolkit, or a collection of libraries, which
developers can use to develop GUI applications for
Linux, OSX, Windows, and any other platform on
which GTK+ is available.
Table of Contents
Part 1 - Designing a User Interface Using Glade 3 ___________________________________________1
Quick Overview of GTK+ Concepts ______________________________________________________________1
Introduction to Glade3 _________________________________________________________________________3
Getting Familiar with the Glade Interface_______________________________________________________3
Manipulating Widget Properties________________________________________________________________5
Specifying Callback Functions for Signals _______________________________________________________6
Adding Widgets to the GtkWindow _____________________________________________________________9
How Packing Effects the Layout ______________________________________________________________ 13
Editing the Menu (or Toolbar) ________________________________________________________________ 15
Final Touches to the Main Window ___________________________________________________________ 18
Part 2 - Choosing a Programming Language for GT K+ Dev elopm ent _____________ 19
Which is the BEST Language? ________________________________________________________________ 19
Language Choice Considerations _____________________________________________________________ 19
A Look at Python vs. C________________________________________________________________________ 20
Part 3 __________________________________________________________________________________________ 22
Setting Up Your Development Environment___________________________________________________ 22
GtkBuilder and LibGlade _____________________________________________________________________ 24
The Minimal Application _____________________________________________________________________ 25
Compiling and Running the Application ______________________________________________________ 27
Stepping Through the Code ___________________________________________________________________
Including the GTK+ Library _______________________________________________________________
Initializing the GTK+ Library ______________________________________________________________
Building the Interface with GtkBuilder ____________________________________________________
Getting References to Widgets From GtkBuilder _________________________________________
Connecting Callback Functions to Signals _______________________________________________
Showing the Application Window _________________________________________________________
In Summary _______________________________________________________________________________
29
29
29
30
32
33
36
37
As you can see, a GtkWindow is derived from GtkBin which is derived from
GtkContainer, and so on. For your first application, you don't need to worry about
anything above the GtkWidget object. The reason this heirarchy is so important is
because when you're looking for functions, properties, and signals for any particular
widget, you need to realize that the functions, properties, and signals of it's parent
objects apply to it as well. In part 2, this will become even more apparent when writing
code for this example application.
We also begin to see a naming convention emerge. This is pretty handy. We can
easily tell what library an object or function is from. All objects beginning with Gtk are
from GTK+. Later, we'll see things like GladeXML which is part of Libglade or GError
which is part of GLib. All objects (and thus Widgets) are incamel case. The functions
which manipulate these objects are in lower-case with underscores for spaces. For
example, gtk_window_set_title() is a function to set the title property of a GtkWindow
object.
All the reference documentation you will need is available online
from library.gnome.org/devel/references,
however,
it
is
much
easier
to
use Devhelp which is likely available as a package for your distribution. Devhelp allows
you to browse and search the API documentation for the libraries you have installed on
your system (assuming you install that libraries documentation as well).
More information on GTK+ and Glib:
Foundations of GTK+ Development (book)
GTK+ 2.0 Tutorial
GTK+ - The GIMP Toolkit
Introduction to Glade3
Glade is a RAD (Rapid Application Development) tool for designing GTK+
applications. Glade is a GTK+ application itself. It is simply a piece of software
developers use to simplify the process of laying out an application's interface. Glade
creates what will hereforth be refered to a s a "glade file". A glade file is actually an
XML file which describes the heirachy of the widgets comprising the interface.
Glade originally generated C code to build the GUI (and you'll still find examples
and tutorials doing this). This was later discouraged in favor of using a library,
Libglade, to build the interface at run time. And finally, as of Glade3, the old method
has become deprecated. That means the ONLY thing glade does is allow you to
generate a glade file which describes how the GUI is going to be built. This allows
more flexibility with the developer, prevents having to re-compile applications when a
minor interface change is needed, and allows more programming languages to be
used with Glade.
Glade3 has had significant changes since previous versions such as Glade2.
Glade3 has been available for some time and you shouldn't have any problems
obtaining it. The package manager for your distribution (yum, aptitude, etc.) should
have Glade3 available. You should note however, that the package will have 3 in it.
Where 'glade' may be the name for the old package, 'glade-3' or 'glade3' will be the
package name for the new version on which this tutorial is based. Glade is also
available from source at glade.gnome.org.
So, the verfy first thing we're going to do, is create a Toplevel widget and save
our file. To do this, Click on the GtkWindow icon
in the Palette under the
'Toplevels' section. You should notice a gray box show up inside the Editor area of
Glade. This is the workable area of a GtkWindow. The titlebar, close button, etc. will be
added to the widget by the window manager (ie: GNOME) so we don't see it while
editing. We will always start with a toplevel widget in Glade, typically a GtkWindow.
Before going further, save the file as "tutorial.glade".
Now the file you just saved, "tutorial.glade", is an XML file. If you were to open it up in a
text editor, it would look something like this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.0 on Tue Nov 20 14:05:37 2007 -->
<glade-interface>
<widget class="GtkWindow" id="window1">
<property name="events">GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK</property>
<child>
<placeholder/>
</child>
</widget>
</glade-interface>
As you can see, it's just a simple XML file. In part2 we will be using C with
Libglade to parse this XML file and generate the UI at run-time. Being XML, this could
just as easily be parsed by a Python program or any other language. As we continue to
work in Glade, this file will be updated to describe our interface in this XML format any
time we save. Exit out of your text editor and return to Glade.
We'll discuss the 'Packing' tab in a bit, but first, let's look at the 'Common' tab.
This tab also contains properties which belong to our GtkWindow, however, we don't
see them in the reference documentation for GtkWindow. This is because this is where
we set properties which areinherited from parent objects. Looking at the reference
documentation for a GtkWidget in the section called "Object Hierarchy", you'll see the
objects from which GtkWindow is derived. Click on the GtkContainer link to jump to
the reference documentation for a GtkContainer. You'll notice that GtkContainer has a
property called "border-width" and we have a property in Glade for "Border width" at
the bottom of the 'Common' tab. We'll learn more about what a container widget is
later, however, this demonstrates how important that object heirarchy is. Since many
widgets are derived from GtkContainer, Glade puts it's properties into the 'Common'
tab.
In the "Object Hierarchy" section of the reference documentation for a
GtkContainer you'll see that it is derived from a GtkWidget. Now click the GtkWidget
link in to jump to the reference documentation for a GtkWidget. The GtkWidget has a
bunch of properties, many of which are also shown in the 'Common' tab of Glade's
Properties pane. These are properties which are common to all GTK+ widgets since all
GTK+ widgets are derivitives of GtkWidget.
Look at the 'Signals' tab in the Glade Properties pane. You see a tree view where
GtkWindow and each of the objects from which it is derived are listed. If you expand
the GtkObject, you'll see all the signals emitted by GtkObject. These correspond to the
reference documentation for a GtkObject in the "Signals" section.
Under the 'Handler' column, click the gray text "<Type here>" to begin editing.
Select 'on_window_destroy' from the drop down and then hit ENTER. We can type
anything we want here, however, glade provides a drop-down list of some of the mroe
common callback function naming conventions. How this value is used depends on
how the programmer connects signals in the code, however, for this tutorial, we want
the GtkWindow's "destroy" signal to be associated with the handler string
"on_window_destroy". We'll look at this closer in Part 2.
At this point, we actually have a working GUI. We could write a few lines of code
in C, Python, Ruby, or any number of programming languages which would show our
empty window and then properly terminate when we clicked the "x" in the titlebar. For
this tutorial however, I will be showing you how to build the entire GUI in Glade3 before
writing any code. However, to satisfy any possible curiosity, if you would like to see
what a simple program looks like that would implement this Glade interface so far...
In C
/*
First
command:
run
tutorial.glade
through
gtk-builder-convert
with
this
*builder;
GtkWidget
*window;
In Python (note: you must set the 'visible' property of 'window' to "Yes" in the
'Common' properties tab in Glade)
#!/usr/bin/env python
# First
command:
run
tutorial.glade
through
gtk-builder-convert
with
this
"on_window_destroy"
gtk.main_quit
})
self.window = builder.get_object("window")
self.window.show()
if __name__ == "__main__":
app = TutorialApp()
gtk.main()
Again, I'm not going to go over the details of the code used to implement this GUI
in this part of the tutorial, but instead focus on using Glade3. However, you can see
that implementing an interface designed in Glade is just a few lines of code in the
language of your choosing!
packing properties and nesting containers, we can have complex GUI designs without
having to write code to handler the resizing and re-positioning of our widgets.
This is probably one of the more difficult concepts for a new GTK+ developer, so
let's just see it in action!
The GtkWindow is a derivative of the container GtkBin which is a container that
contains only one child widget. But this text editor is going to have 3 main sections; a
menu bar, a text editing area, and a status bar. Therefore, we use a fundamental
GTK+ widget, the GtkVBox. The GtkVBox (vertical box) is a container widget which
can contain any number of child widgets stacked up vertically like rows (GtkHBox is
the horizontal equivelant).
Click on the GtkVBox icon
in the Glade Palette under the 'Containers' section.
You'll notice that the 'Select' toolbar button on the top of the Glade window is no longer
depressed and your mouse cursor is the GtkVBox icon with a plus (+) sign when
hovering over the Glade Editor. This means you are ready to drop the GtkVBox
somewhere. Click in gray area of the Editor which is the empty space of the
GtkWindow.
A dialog box pops up asking you for the 'Number of items'. In this case we want 3
rows, so leave it as 3 and click 'OK'.
You should see the GtkWindow in the Editor divided into 3 rows now. These are
the 3 empty child widgets of the GtkVBox we just added. You should also notice that
the 'Select' toolbar at the top of Glade is once again depressed--allowing you to select
widgets within the Editor.
10
11
And there you have it; the basic layout of our GTK+ text editor. If you look at the
Glade Inspector you will see the parent-child relationship of our design.
The Inspector will come in handy. You cannot always click on a widget in the
Editor as it might not be visible. For example, you cannot click on the
GtkScrolledWindow we added, because you can only see it's child, the GtkTextView.
12
Therefore, if you need to change the properties of "scrolledwindow1", you will have to
select it in the Inspector.
I mentioned earlier how "packing" is an often frustrating concept to new GTK+
developers. Therefore, I'm going to show you first hand how various packing effects
the layout of your design.
Property
Value
GtkVBox "vbox1"
homogeneous
FALSE
GtkMenuBar "menubar1"
expand
FALSE
fill
TRUE
expand
TRUE
GtkScrolledWindow
"scrolledwindow1"
13
GtkStatusbar "statusbar1"
fill
TRUE
expand
FALSE
fill
TRUE
Now, let's see what homogeneous does. Select the GtkVBox in the
Inspector and change it's "Homogeneous" property under 'General' properties
"Yes". Now the parent, "vbox1", allocates the same amount of space to each
children. Since all 3 child widgets have "fill"=TRUE, they fill up this extra
allocated to them.
Glade
tab to
of it's
space
14
Now set the "Expand" property of the GtkScrolledWindow back to "Yes" and
change the "Fill" property to "No" instead. This time, the extra space is allocated to the
GtkScrolledWindow since "expand"=TRUE, however, the GtkScrolledWindow doesn't
use the space it was allocated since "fill"=FALSE.
Set the "Fill" property back to "Yes" to restore our original packing properties.
I know it seems odd at first, but as you continue to work in Glade, you'll start to
pick up on how these packing properties work and once you've conquored that part of
the learning curve, you'll be amazed at how little work you have to do related to the
position and size of your GUI's elements.
15
The menu editor contains properties just like Glade's main Properties pane and
signals at the bottom just like the 'Signals' tab of Glade's main Properties pane. The
main difference in the editor is the tree view on the left. It allows you easily add and
remove menu items and drag them around. Go ahead and remove the one labeled
"_View". This is the only menu item which Glade generates that we won't be using in
this tutorial.
For the remaining menu items we will need to do a few things. We need to
rename them so that we have a clean, legible way to reference them in our source
code. Then, we'll make some changes as a work around to a bug that might effect
some readers using GTK+ 2.12.9 or below (Bug #523932), and finally we'll specify
signal handlers. The steps for each of the menu items will be the same, so I'll just walk
you through the 'New' menu item. Remember, this is all done in the menu editor but
can also be done using the Inspector and Properties pane in glade.
1. Click on the new menu item 'gtk-new'
2. Change the 'Name' property under 'Menu Item' to "new_menu_item"
3. Change the 'Label' property under 'Properties' to "_New" (note the
underscore, that's an accellerator)
4. Change the 'Stock Item' property under 'Properties' to "None"
5. Click on another menu item such as 'gtk-open' and then click back to 'gtknew' to refresh the properties (Bug #533503)
6. Change the 'Stock Image' under 'Internal Image Properties' to the 'New'
image
7. Specify
a
handler
for
the
"activate"
signal
callled
"on_new_menu_item_activate" (This is done just like before, where we click
the tree view to get a drop down list of possible signal names)
16
Now repeat those steps for each of the menu items: 'gtk-open', 'gtk-save', etc.
Below are screen shots of the before and after on the 'New' menu item:
17
18
19
20
an experienced programmer with C, C++, or Java experience you may want to learn
Python. It's an exciting modern language, fun to program with, and incredible quick to
learn and use. For Rapid Application Development in Linux, Glade and Python make a
great team. Learn more about the Python GTK+ binding PyGTK at www.pygtk.org.
If you're an experienced programmer or dedicated student, it may be worth your
while to learn C or C++ for GTK+ development--especially if you're already familiar
with C or C++. Learning GTK+ in C makes switching to another language such as
Python a breeze. Furthermore, you'll have more options for contributing to existing
projects. Personally, I do the majority of my GTK+ development in C despite the extra
time it takes.
21
22
is a plugins
written Gedit
your source
tutorial (click
Working in C
Working in Python
The development libraries you will need depend both on your distribution and
whether you want to work in Python or C. Although the process can vary greatly
23
depending on your platform and distribution, I can give you the information you need to
get started. If you have problems installing any of the packages you need, post your
problem or question at the GTK+ Forums or a forum for your distribution.
When it comes to development libraries with Linux, you can often get all the
packages you need using your distributions package manager to resolve
dependencies. For example, on Ubuntu you can likely just issue the command: 'sudo
aptitude install libgtk-2.0-dev'. This command will install the GTK+ development
package, it's dependencies, their dependencies, and so on.
It's important to install the "development packages". These are suffixed with "dev" in Ubuntu/Debian and "-devel" in Redhat/Fedora. The development packages
include header files and other includes that allow you to build applications which use a
particular library. Just remember, "package" allows you to run applications using that
library where "package-dev" or "package-devel" allows you to write applications using
that library.
Another prefix you will see on packages is "-doc" such as "libgtk2.0-doc". This will
be the documentation for that library and once installed will allow you to browse the
documentation using Devhelp: the GNOME developer's help browser.
If you're programming with C you should install the following packages with their
dependencies: build-essential, libgtk2.0-dev, libgtk2.0-doc, libglib2.0-doc, devhelp
(package names may vary depending on distribution, these are for Ubuntu).
If you're programming with Python you should install the following packages with
their dependencies: python2.5-dev python2.5-doc, python2.5-gtk2, python-gtk2-doc,
python-gobject-doc, devhelp (package names may vary depending on distribution,
these are for Ubuntu).
24
Since (at the time of writing) GtkBuilder is relatively new, Glade does not yet
support saving in the GtkBuilder format. The GtkBuilder format is still an XML file, but
with a slightly different schema. That means that in order to use GtkBuilder on a glade
file, we must first convert it to the GtkBuilder format. GTK+ 2.12 provides a conversion
script for this process, and will already be installed on your system at this point.
You can read some of the common questions
Libglade/GtkBuilder stuff at Libglade to GtkBuilder F.A.Q..
I get
So we now convert the glade XML file tutorial.glade to the GtkBuilder XML file
tutorial.xml with the following command:
gtk-builder-convert tutorial.glade tutorial.xml
The file 'tutorial.xml' is the file we will actually parse in our program, however, we
still need tutorial.glade when we want to make changes using Glade. This is only
necessary until Glade supports the GtkBuilder format in a later version (They are
aiming to have this ready by Glade 3.6 which you can follow along Bug #490678).
25
gtk_main_quit();
}
int
main (int argc, char *argv[])
{
GtkBuilder
*builder;
GtkWidget
*window;
GTK_WIDGET
(gtk_builder_get_object
"window"));
gtk_builder_connect_signals (builder, NULL);
g_object_unref (G_OBJECT (builder));
gtk_widget_show (window);
gtk_main ();
return 0;
}
26
(builder,
builder.connect_signals(self)
if __name__ == "__main__":
editor = TutorialTextEditor()
editor.window.show()
gtk.main()
The output should show the version of GTK+ you have installed. On my system it
shows '2.12.0'. Now let's look at what compiler flags are needed to build a GTK+
application on my system:
pkg-config --cflags gtk+-2.0
The output of that command shows a bunch of -I switches which are specifying
include paths for the compiler to use. This will tell gcc where to look for include files
when we use '#include' in our application. The very first one on my system is 'I/usr/include/gtk-2.0'. That means that when I use '#include <gtk/gtk.h>' in my code,
gcc will be able to find '/usr/include/gtk-2.0/gtk/gtk.h'.
Anytime you use a '#include <library/header.h>' style include that is not part of
the standard C library in your code, there should be a '-I/path/to/library' style option
passed to gcc. These libraries can be installed in different locations based on
distribution, operating system, or user preference. Good thing we have pkg-config to
handle all of this for us!
Let's compile our application so far. Issue this command in the terminal (make
sure you are in the same directory in which both 'main.c' and 'tutorial.xml' reside:
27
The '-Wall' option tells gcc to show all warnings. The '-g' option will generate
debugging information which will be useful should you have a bug in your application
and need to step through the code using a debugger such as gdb. The option '-o
tutorial' tell gcc to generate the output executable into a file named 'tutorial'. 'main.c' is
the file gcc will compile. The '-export-dynamic' has to do with how we connect signals
to callback functions which will be discussed when we step through the code. And
finally, the pkg-config command appears.
Notice how it is enclosed in backticks (those are not single quotes). The backtick
is usually to the left of the '1' key on th e keyboard with the tilde character (~). This is
telling our shell to first execute the command 'pkg-config --cflags --libs gtk+-2.0' and
put the output of that command into the current command. So if you execute 'pkgconfig --cflags --libs gtk+-2.0' on your system and then paste it's output onto the end of
that gcc command, it would be virtually the same thing. By using pkg-config to append
the include paths and library paths to our compile command, we can use the same
command to compile our program on any system, regardless of where those libraries
are installed.
After your application compiles, there should be a new executable file named
'tutorial' which you execute using:
./tutorial
When you do so, you are going to see several warnings from GTK, something
along the lines of " Gtk-WARNING **: Could not find signal handler 'xxxxxx'". Don't
worry about those for now. Those are telling use that we specified a signal handler in
our glade file which we did not yet write a function for. I'll address these when we step
through the code. But you should have seen your GTK+ Text Editor window show up,
and clicking the 'x' in the window titlebar should properly terminate the application.
If for some reason you were not able to get the application to compile or execute,
post your error messages and any other information in the GTK+ Forums.
If you're programming in Python
Since Python is an Interpreted Language we don't need to compile our program.
We simply invoke the Python interpreter, which we actually do with the first line in our
source code. So all we need to do to run our Python program, is change the
permissions so that the file is executable and then run it. Change the permissions
using:
chmod a+x tutorial.py
28
you should have seen your GTK+ Text Editor window show up, and clicking the
'x' in the window titlebar should properly terminate the application.
If for some reason you were not able to get the application to compile or execute,
post your error messages and any other information in the GTK+ Forums.
29
If you're programming in C
gtk_init (&argc, &argv);
Looking in 'main()' we see that we initialize GTK+ before anything else using
the gtk_init() function.
Building the Interface with GtkBuilder
In a GTK+ application written entirely through code, that is, without the
assistance of Glade or another interface designer, we would have to
programatically create each widget, set the various properties of that widget, and
add it to it's parent widget where applicable. Each of these steps could require
several lines of code for each widget. That can be tedious. Just think about the
interface we created in part 1. There are over 20 widgets defined (including all
the menu items). To create all those widgets through pure code could exceed a
hundred lines of lines of code once all the properties were applied!
Good thing we're using Glade and GtkBuilder. With just 2 lines of code,
GtkBuilder will open and parse tutorial.xml, create all the widgets defined within,
apply their properties, and establish the widgets' parent-child relationships. Once
that is done we can then ask builder for the references to the widgets we want to
further manipulate or otherwise reference.
30
If you're programming in C
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "tutorial.xml", NULL);
31
You will notice that after calling gtk_builder_new() to create a new builder object,
all the other gtk_builder_xxx functions take that builder object as the first parameter.
This is how GTK+ implements object oriented programming in C, and will be consistent
with all GTK+ objects (compare that with how Python, a natural OOP language
implements the same thing below).
If you're programming in Python
builder = gtk.Builder()
builder.add_from_file("tutorial.xml")
32
pointer to a GtkWidget. Moreover, we know that the object we are trying to get was a
GtkWindow. This is why I placed so much emphasis on the 'Object Hierarchy' of
widgets and GTK+ objects. If you look at the Object Hierarchy for a GtkWindow you
will see that GtkWidget is one of it's ancestors as is GObject. Therefore, a
GtkWindow is a GObject and it is a GtkWidget. This is a fundamental OOP concept
and critical to working with GTK+.
So, the GTK_WIDGET() wrapped around the call to gtk_builder_get_object() is a
convenience macro used for casting. You can cast a GTK+ widget into any of it's
ancestors using one of these casting macros. All GTK+ objects will have them
available. So, 'GTK_WIDGET(something)' is the same as '(GtkWidget*)something'.
We're casting the pointer to a GObject returned from the call to
gtk_builder_get_object() to a pointer to a GtkWidget as that's what 'window' was
declared as.
Finally, the reason we declared window as a pointer to a GtkWidget in the
beginning of main() rather than as a pointer to a GtkWindow is due to convention. We
could have declared it as a GtkWindow* and that would have still been correct. All
GTK+ widgets are derived from a GtkWidget so we can always declare a variable
pointing to any GTK+ widget as such. Many functions take GtkWidget* as a paramter
and many functions return GtkWidget* and thus it usually makes sense to declare your
variables as such and simply cast them to the specific widget where applicable (which
you'll see later).
If you're programming in Python
self.window = builder.get_object("window")
We are using gtk.Builder.get_object() to get the object named "window" from the
builder. This corresponds to the 'name' we specified for the widget in Glade during part
1. If you recall, we named the main application's GtkWindow 'window'. So, that's what
we pass to get_object(). We assign the returned object to self.window so that we have
access to the application's window anywhere within the TutorialTextEditor() class.
Connecting Callback Functions to Signals
In part 1 we specified "handlers" for various "signals" in our interfac e. If you
recall, GTK+ emits signals for various events that occur. This is a fundamental concept
of GUI programming. Our application needs to know when the user does something so
that it can respond to that action. As we'll see soon, our application just sits around in a
loop waiting for something to happen. We will be using GtkBuilder to connect the
signal handlers we defined using Glade with callback functions in our code. GtkBuilder
will look at our code's symbols and connect the appropriate handlers for us.
33
So now gtk_builder_connect_signals() will find this function and see that it both
matches the name of the handler we specified in Glade and has a compatible
34
signature (takes the same arguments) as that specified for the "destroy" signal and
makes the connection. Now our function on_window_destroy() will be called when the
GtkWindow 'window' is destroyed.
In on_window_destroy() we just call gtk_main_quit() to properly terminate our
application. This function will break out of the main loop which I will talk about more
when we get there in just a bit.
Right after the
to g_object_unref().
call
to
gtk_builder_connect_signals()
there
was
call
This is because we are no longer going to use the GtkBuilder object. We used it
to construct our widgets and then we obtained pointers to the widgets we needed to
reference. So now we can free all the memory it used up with XML stuff.
You'll also noticed that we are using one of those casting macros to cast
(GtkBuilder*) to (GObject*). We must do this because g_object_unref() takes a
GObject* as a parameter. Since a GtkBuilder is derived from a GObject (as are all
widgets) this is perfectly valid.
If you're programming in Python
builder.connect_signals(self)
So now builder.connect_signals() will find this method and see that it both
matches the name of the handler we specified in Glade and has a compatible
signature (takes the same arguments) as was specified for the "destroy" signal and
makes the connection. Now our method on_window_destroy() will be called when the
GtkWindow 'window' is destroyed.
35
Calling gtk.Widget.show() tells GTK+ to show the widget (which will happen
within the GTK+ main loop discussed next).
Entering the GTK+ Main Loop
The main loop in GTK+ is an infinite loop which performs all of the "magic". This
is how GUI programming works. Once we build our GUI and setup our program, we
enter the GTK+ main loop and just wait for an event to occur which we care about
(such as closing the window). A lot is happening inside this main loop, however, for a
beginner you can simply think of it as an infinate loop in which GTK+ checks the state
of things, updates the UI, and emits signals for events.
After entering the main loop, our application isn't doing anything (but GTK+ is).
When the user resizes the window, minimizes it, clicks on it, presses keys, etc. GTK+
is checking each of these events and emitting signals for them. However, our
application is only connected to one signal currently, the "destroy" signal of 'window'.
When the window is closed and the "destroy" signal is emitted, then the GTK+ main
loop will turn over control to the handler function we have connected to that signal
which breaks us out of the GTK+ main loop thus allowing our application to terminate.
If you're programming in C
gtk_main ();
36
gtk.main()
In Summary
1. Application uses GtkBuilder to create the GUI from XML file.
2. Application gets reference to main window widget.
3. Application connects 'on_window_destroy' handler to the "destroy" signal.
4. Application flags the window to be shown.
5. Application enters GTK+ main loop (window is shown).
6. User clicks the 'x' in the titlebar as a result of which GTK+ main loop emits
the "destroy" signal.
7. Handler 'on_window_destroy' breaks out of GTK+ main loop.
8. Application terminates normally.
37