    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: An Introduction to Programming with GTK+ and Glade in ISO C
and ISO C++</title>
        <link>https://members.accu.org/index.php/articles/680</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + CVu Journal Vol 16, #4 - Aug 2004</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c77/">CVu</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c101/">164</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-101/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+101/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;An Introduction to Programming with GTK+ and Glade in ISO C
and ISO C++</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 03 August 2004 13:16:06 +01:00 or Tue, 03 August 2004 13:16:06 +01:00</p>
<p><strong>Summary:</strong>&nbsp;<p>This short tutorial is intended as a simple introduction to writing GTK+ applications in C and C++, using the current 2.0/2.2 version of libgtk. It also covers the use of the Glade user interface designer for rapid application development (RAD).</p></p>
<p><strong>Body:</strong>&nbsp;<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e20" id="d0e20"></a>What is
GTK+?</h2>
</div>
<p>GTK+ is a <span class="emphasis"><em>toolkit</em></span> used
for writing graphical applications. Originally written for the X11
windowing system, it has now been ported to other systems, such as
Microsoft Windows and the Apple Macintosh, and so may be used for
cross-platform software development. GTK+ was written as a part of
the <span class="emphasis"><em>GNU Image Manipulation
Program</em></span> (GIMP), but has long been a separate project,
used by many other free software projects, one of the most notable
being the <span class="emphasis"><em>GNU Network Object Model
Environment</em></span> (GNOME) Project.</p>
<p>GTK+ is written in C and, because of the ubiquity of the C
language, <span class="emphasis"><em>bindings</em></span> have been
written to allow the development of GTK+ applications in many other
languages. This short tutorial is intended as a simple introduction
to writing GTK+ applications in C and C++, using the current
2.0/2.2 version of <tt class="literal">libgtk</tt>. It also covers
the use of the Glade user interface designer for <i class=
"firstterm">rapid application development</i> (RAD).</p>
<p>It is assumed that the reader is familiar with C and C++
programming, and it would be helpful to work through the &quot;Getting
Started&quot; chapter of the GTK+ tutorial before reading further. The
<tt class="literal">GTK+</tt>, <tt class="literal">Glib</tt>,
<tt class="literal">libglade</tt>, <tt class="literal">Gtkmm</tt>
and <tt class="literal">libglademm</tt> API references will be
useful while working through the examples.</p>
<p>I hope you find this tutorial informative.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e64" id="d0e64"></a>Building the
Example Code</h2>
</div>
<p>Several working, commented examples accompany the tutorial. They
are also available from <a href=
"http://people.debian.org/~rleigh/gtk/ogcalc/" target=
"_top">http://people.debian.org/~rleigh/gtk/ogcalc/</a>. To build
them, type:</p>
<pre class="screen">
./configure
make
</pre>
<p>This will check for the required libraries and build the example
code. Each program may then be run from within its
subdirectory.</p>
<p>I have been asked on various occasions to write a tutorial to
explain how the GNU autotools work. While this is not the aim of
this tutorial, I have converted the build to use the autotools as a
simple example of their use.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e78" id="d0e78"></a>Legal Bit</h2>
</div>
<p>This tutorial document, the source code and compiled binaries,
and all other files distributed in the source package are copyright
&copy; 2003 - 2004 Roger Leigh. These files and binary programs are
free software; you can redistribute them and/or modify them under
the terms of the GNU General Public Licence as published by the
Free Software Foundation; either version 2 of the Licence, or (at
your option) any later version.</p>
<p>A copy of the GNU General Public Licence version 2 is provided
in the file COPYING in the source package this document was
generated from.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e85" id="d0e85"></a>GTK+
Basics</h2>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e88" id="d0e88"></a>Objects</h3>
</div>
<p>GTK+ is an <i class="firstterm">object-oriented</i> (OO)
toolkit. I'm afraid that unless one is aware of the basic OO
concepts (classes, class methods, inheritance, polymorphism), this
tutorial (and GTK+ in general) will seem rather confusing. On my
first attempt at learning GTK+, I didn't &quot;get&quot; it, but after I
learnt C++, the concepts GTK+ is built on just &quot;clicked&quot;, and I
understood it quite quickly.</p>
<p>The C language does not natively support classes, and so GTK+
provides its own object/type system, GObject. GObject provides
objects, inheritance, polymorphism, constructors, destructors and
other facilities such as reference counting and signal emission and
handling. Essentially, it provides C++ classes in C. The syntax
differs a little from C++ though. As an example, the following
C++</p>
<pre class="programlisting">
myclass c;
c.add(2);
</pre>
<p>would be written like this using GObject:</p>
<pre class="programlisting">
myclass *c = myclass_new();
myclass_add(c, 2);
</pre>
<p>The difference is due to the lack of a this pointer in the C
language (since objects do not exist). This means that class
methods require the object pointer passing as their first argument.
This happens automatically in C++, but it needs doing &quot;manually&quot; in
C.</p>
<p>Another difference is seen when dealing with polymorphic
objects. All GTK+ widgets (the controls, such as buttons,
checkboxes, labels, etc.) are derived from <tt class=
"classname">GtkWidget</tt>. That is to say, a <tt class=
"classname">GtkButton</tt> <span class="emphasis"><em>is
a</em></span> <tt class="classname">GtkWidget</tt>, which
<span class="emphasis"><em>is a</em></span> <tt class=
"classname">GtkObject</tt>, which <span class="emphasis"><em>is
a</em></span> <tt class="classname">GObject</tt>. In C++, one can
call member functions from both the class and the classes it is
derived from. With GTK+, the object needs explicit casting to the
required type. For example</p>
<pre class="programlisting">
GtkButton mybutton;
mybutton.set_label(&quot;Cancel&quot;);
mybutton.show();
</pre>
<p>would be written as</p>
<pre class="programlisting">
GtkButton *mybutton = gtk_button_new();
gtk_button_set_label(mybutton, &quot;Cancel&quot;);
gtk_widget_show(GTK_WIDGET(mybutton))
</pre>
<p>In this example, <tt class="methodname">set_label()</tt> is a
method of <tt class="classname">GtkButton</tt>, whilst <tt class=
"methodname">show()</tt> is a method of <tt class=
"classname">GtkWidget</tt>, which requires an explicit cast. The
<tt class="literal">GTK_WIDGET()</tt> cast is actually a form of
<i class="firstterm">run-time type identification</i> (RTTI). This
ensures that the objects are of the correct type when they are
used.</p>
<p>Objects and C work well, but there are some issues, such as a
lack of type-safety of callbacks and limited compile-time type
checking. Using <tt class="classname">GObject</tt>, deriving new
widgets is complex and error-prone. For these, and other, reasons,
C++ may be a better language to use. <tt class=
"literal">libsigc++</tt> provides type-safe signal handling, and
all of the GTK+ (and <tt class="literal">GLib</tt>, Pango et. al.)
objects are available as standard C++ classes. Callbacks may also
be class methods, which makes for cleaner code, since the class can
contain object data without having to resort to passing in data as
a function argument. These potential problems will become clearer
in the next sections.</p>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e169" id="d0e169"></a>Widgets</h3>
</div>
<p>A user interface consists of different objects with which the
user can interact. These include buttons which can be pushed, text
entry fields, tick boxes, labels and more complex things such as
menus, lists, multiple selections, colour and font pickers. Some
example widgets are shown in Figure 1.</p>
<p>Not all widgets are interactive. For example, the user cannot
usually interact with a label, or a framebox. Some widgets, such as
containers, boxes and event boxes are not even visible to the user
(there is more about this in the next section).</p>
<p>Different types of widget have their own unique <span class=
"emphasis"><em>properties</em></span>. For example, a label widget
contains the text it displays, and there are functions to get and
set the label text. A checkbox may be ticked or not, and there are
functions to get and set its state. An options menu has functions
to set the valid options, and get the option the user has
chosen.</p>
<div class="figure"><a name="d0e181" id="d0e181"></a>
<div class="mediaobject c2"><img src=
"resources/gtk-all-gui-elements.png" align="middle" alt=
"A selection of GTK+ widgets"></div>
<p class="title c3">Figure 1. A selection of GTK+ widgets</p>
</div>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e187" id="d0e187"></a>Containers</h3>
</div>
<p>The top-level of every GTK+ interface is the <span class=
"emphasis"><em>window</em></span>. A window is what one might
expect it to be: it has a title bar, borders (which may allow
resizing), and it contains the rest of the interface.</p>
<p>In GTK+, a <tt class="classname">GtkWindow</tt> <span class=
"emphasis"><em>is a</em></span> <tt class=
"classname">GtkContainer</tt>. In English, this means that the
window is a widget that can contain another widget. More precisely,
a <tt class="classname">GtkContainer</tt> can contain exactly one
widget. This is usually quite confusing compared with the behaviour
of other graphics toolkits, which allow one to place the controls
on some sort of &quot;form&quot;.</p>
<p>The fact that a <tt class="classname">GtkWidget</tt> can only
contain one widget initially seems quite useless. After all, user
interfaces usually consist of more than a single button. In GTK+,
there are other kinds of <tt class="classname">GtkContainer</tt>.
The most commonly used are horizontal boxes, vertical boxes, and
tables. The structure of these containers is shown in Figure 2.</p>
<p>Figure 2 shows the containers as having equal size, but in a
real interface, the containers resize themselves to fit the widgets
they contain.</p>
<div class="figure"><a name="d0e219" id="d0e219"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/gtk-containers.png"
align="middle" alt="GTK+ containers">
<div class="caption">
<p>Each container may contain other widgets in the shaded areas.
Containers may contain more containers, allowing them to nest.
Complex interfaces may be constructed by nesting the different
types of container.</p>
</div>
</div>
<p class="title c3">Figure 2. GTK+ containers</p>
</div>
<p>In other cases, widgets may be expanded or shrunk to fit the
space allotted to them. There are several ways to control this
behaviour, to give fine control over the appearance of the
interface.</p>
<p>In addition to the containers discussed above, there are more
complex containers available, such are horizontal and vertical
panes, tabbed notebooks, and viewports and scrolled windows. These
are out of the scope of this tutorial, however.</p>
<p>Newcomers to GTK+ may find the concept of containers quite
strange. Users of Microsoft Visual Basic or Visual C++ may be used
to the free-form placement of controls. The placement of controls
at fixed positions on a form has <span class=
"emphasis"><em>no</em></span> advantages over automatic positioning
and sizing. All decent modern toolkits use automatic positioning.
This fixes several issues with fixed layouts:</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>The hours spent laying out forms, particularly when maintaining
existing code.</p>
</li>
<li>
<p>Windows that are too big for the screen.</p>
</li>
<li>
<p>Windows that are too small for the form they contain.</p>
</li>
<li>
<p>Issues with spacing when accommodating translated text.</p>
</li>
<li>
<p>Bad things happen when changing the font size from the
default.</p>
</li>
</ul>
</div>
<p>The nesting of containers results in a <i class=
"firstterm">widget tree</i>, which has many useful properties, some
of which will be used use later. One important advantage is that
they can dynamically resize and accommodate different lengths of
text, important for internationalisation, when translations in
different languages may vary widely in their size.</p>
<p>The Glade user interface designer can be very instructive when
exploring how containers and widget packing work. It allows easy
manipulation of the interface, and all of the standard GTK+ widgets
are available. Modifying an existing interface is trivial, even
when doing major reworking. Whole branches of the widget tree may
be cut, copied and pasted at will, and a widget's properties may be
manipulated using the &quot;Properties&quot; dialogue. While studying the
code examples, Glade may be used to interactively build and
manipulate the interface, to visually follow how the code is
working. More detail about <tt class="literal">Glade</tt> is
provided in a later section, where libglade is used to dynamically
load a user interface.</p>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e263" id="d0e263"></a>Signals</h3>
</div>
<p>Most graphical toolkits are <span class=
"emphasis"><em>event-driven</em></span>, and GTK+ is no exception.
Traditional console applications tend not to be event-driven; these
programs follow a fixed path of execution. A typical program might
do something along these lines:</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>Prompt the user for some input</p>
</li>
<li>
<p>Do some work</p>
</li>
<li>
<p>Print the results</p>
</li>
</ul>
</div>
<p>This type of program does not give the user any freedom to do
things in a different order. Each of the above steps might be a
single function (each of which might be split into helper
functions, and so on).</p>
<p>GTK+ applications differ from this model. The programs must
react to events, such as the user clicking on a button, or pressing
Enter in an text entry field. These widgets emit signals in
response to user actions. For each signal of interest, a function
defined by the programmer is called. In these functions, the
programmer can do whatever needed. For example, in the <tt class=
"literal">ogcalc</tt> program, when the &quot;Calculate&quot; button is
pressed, a function is called to read the data from entry fields,
do some calculations, and then display the results.</p>
<p>Each event causes a <span class=
"emphasis"><em>signal</em></span> to be <span class=
"emphasis"><em>emitted</em></span> from the widget handling the
event. The signals are sent to <span class="emphasis"><em>signal
handlers</em></span>. A signal handler is a function which is
called when the signal is emitted. The signal handler is
<span class="emphasis"><em>connected</em></span> to the signal. In
C, these functions are known as <span class=
"emphasis"><em>callbacks</em></span>. The process is illustrated
graphically in Figure 3.</p>
<p>A signal may have zero, one or many signal handlers connected
(registered) with it. If there is more than one signal handler,
they are called in the order they were connected in.</p>
<p>Without signals, the user interface would display on the screen,
but would not actually do anything. By associating signal handlers
with signals one is interested in, events triggered by the user
interacting with the widgets will cause things to happen.</p>
<div class="figure"><a name="d0e309" id="d0e309"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/signals.png" align=
"middle" alt="A typical signal handler.">
<div class="caption">
<p>When the button is pressed, a signal is emitted, causing the
registered callback function to be called.</p>
</div>
</div>
<p class="title c3">Figure 3. A typical signal handler.</p>
</div>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e318" id="d0e318"></a>Libraries</h3>
</div>
<p>GTK+ is comprised of several separate libraries:</p>
<div class="informaltable">
<table border="0">
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody&gt;
<tr>
<td><tt class="literal">atk</tt></td>
<td>Accessibility Toolkit, to enable use by disabled people.</td>
</tr>
<tr>
<td><tt class="literal">gdk</tt></td>
<td>GIMP Drawing Kit (XLib abstraction layer - windowing system
dependent part).</td>
</tr>
<tr>
<td><tt class="literal">gdk-pixbuf</tt></td>
<td>Image loading and display.</td>
</tr>
<tr>
<td><tt class="literal">glib</tt></td>
<td>Basic datatypes and common algorithms.</td>
</tr>
<tr>
<td><tt class="literal">gmodule</tt></td>
<td>Dynamic module loader (libdl portability wrapper).</td>
</tr>
<tr>
<td><tt class="literal">gobject</tt></td>
<td>Object/type system.</td>
</tr>
<tr>
<td><tt class="literal">gtk</tt></td>
<td>GIMP Tool Kit (windowing system independent part).</td>
</tr>
<tr>
<td><tt class="literal">pango</tt></td>
<td>Typeface layout and rendering.</td>
</tr>
&lt;/tbody&gt;
</table>
</div>
<p>When using <tt class="literal">libglade</tt> another library is
required:</p>
<div class="informaltable">
<table border="0">
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody&gt;
<tr>
<td><tt class="literal">glade</tt></td>
<td>User Interface description loader/constructor.</td>
</tr>
&lt;/tbody&gt;
</table>
</div>
<p>Lastly, when using C++, some additional C++ libraries are also
needed:</p>
<div class="informaltable">
<table border="0">
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody&gt;
<tr>
<td><tt class="literal">atkmm</tt></td>
<td>C++ ATK wrapper.</td>
</tr>
<tr>
<td><tt class="literal">gdkmm</tt></td>
<td>C++ GDK wrapper.</td>
</tr>
<tr>
<td><tt class="literal">gtkmm</tt></td>
<td>C++ GTK+ wrapper.</td>
</tr>
<tr>
<td><tt class="literal">glademm</tt></td>
<td>C++ Glade wrapper.</td>
</tr>
<tr>
<td><tt class="literal">pangomm</tt></td>
<td>C++ Pango wrapper.</td>
</tr>
<tr>
<td><tt class="literal">sigc++</tt></td>
<td>Advanced C++ signal/slot event handling (wraps GObject
signals).</td>
</tr>
&lt;/tbody&gt;
</table>
</div>
<p>This looks quite intimidating! However, there is no need to
worry, since compiling and linking programs is quite easy. Since
the libraries are released together as a set, there are few library
interdependency issues.</p>
</div>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e431" id="d0e431"></a>Designing an
Application</h2>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e434" id="d0e434"></a>Planning
Ahead</h3>
</div>
<p>Before starting to code, it is necessary to plan ahead by
thinking about what the program will do, and how it should do it.
When designing a graphical interface, one should pay attention to
<span class="emphasis"><em>how</em></span> the user will interact
with it, to ensure that it is easy to understand, and efficient to
use.</p>
<p>When designing a GTK+ application, it is useful to sketch the
interface on paper, before constructing it. Interface designers
such as Glade are helpful here, but a pen and paper are best for
the initial design.</p>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e444" id="d0e444"></a>Introducing
<tt class="literal">ogcalc</tt></h3>
</div>
<p>As part of the production (and quality control) processes in the
brewing industry, it is necessary to determine the alcohol content
of each batch at several stages during the brewing process. This is
calculated using the density (gravity) in g/cm3 and the refractive
index. A correction factor is used to align the calculated value
with that determined by distillation, which is the standard
required by HM Customs &amp; Excise. Because alcoholic beverages
are only slightly denser than water, the PG value is <tt class=
"literal">(density-1) x 100</tt>. That is, 1.0052 would be entered
as 52.</p>
<p>Original gravity is the density during fermentation. As alcohol
is produced during fermentation, the density falls. Traditionally,
this would be similar to the PG, but with modern high-gravity
brewing (at a higher concentration) it tends to be higher. It is
just as important that the OG is within the set limits of the
specification for the product as the ABV.</p>
<p>The <tt class="literal">ogcalc</tt> program performs the
following calculation:</p>
<pre class="literallayout">
O = (R x 2.597) - (P x 1.644) - 34.4165 + C
</pre>
<p>If <tt class="literal">O</tt> is less than 60, then</p>
<pre class="literallayout">
A = (O - P) x 0.130
</pre>
<p>otherwise</p>
<pre class="literallayout">
A = (O - P) x 0.134
</pre>
<p>The symbols have the following meanings:</p>
<div class="informaltable">
<table border="0">
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody&gt;
<tr>
<td>A</td>
<td>Percentage Alcohol By Volume</td>
</tr>
<tr>
<td>C</td>
<td>Correction Factor</td>
</tr>
<tr>
<td>O</td>
<td>Original Gravity</td>
</tr>
<tr>
<td>P</td>
<td>Present Gravity</td>
</tr>
<tr>
<td>R</td>
<td>Refractive Index</td>
</tr>
&lt;/tbody&gt;
</table>
</div>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e506" id="d0e506"></a>Designing the
Interface</h3>
</div>
<p>The program needs to ask the user for the values of <tt class=
"literal">C</tt>, <tt class="literal">P</tt>, and <tt class=
"literal">R</tt>. It must then display the results, <tt class=
"literal">A</tt> and <tt class="literal">O</tt>. A simple sketch of
the interface is shown in Figure 4.</p>
<div class="figure"><a name="d0e526" id="d0e526"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/sketch.png" align=
"middle" alt="Sketching a user interface">
<div class="caption">
<p>The ogcalc main window is drawn simply, to illustrate its
functionality. The top row contains three numeric entry fields,
followed by two result fields on the middle row. The bottom row
contains buttons to quit the program, reset the interface and do
the calculation.</p>
</div>
</div>
<p class="title c3">Figure 4. Sketching a user interface</p>
</div>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e535" id="d0e535"></a>Creating the
Interface</h3>
</div>
<p>Due to the need to build up an interface from the bottom up, due
to the containers being nested, the interface is constructed
starting with the window, then the containers that fit in it. The
widgets the user will use go in last. This is illustrated in Figure
5.</p>
<div class="figure"><a name="d0e540" id="d0e540"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/widget-packing.png"
align="middle" alt="Widget packing">
<div class="caption">
<p>The steps taken during the creation of an interface are shown,
demonstrating the use of nested containers to pack widgets.</p>
</div>
</div>
<p class="title c3">Figure 5. Widget packing</p>
</div>
<p>Once a widget has been created, signal handlers may be connected
to its signals. After this is completed, the interface can be
displayed, and the main <span class="emphasis"><em>event
loop</em></span> may be entered. The event loop receives events
from the keyboard, mouse and other sources, and causes the widgets
to emit signals. To end the program, the event loop must first be
left.</p>
</div>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e554" id="d0e554"></a>GTK+ and
C</h2>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e557" id=
"d0e557"></a>Introduction</h3>
</div>
<p>Many GTK+ applications are written in C alone. This section
demonstrates the <tt class="literal">C/plain/ogcalc</tt> program
discussed in the previous section. Figure 6 is a screenshot of the
finished application.</p>
<div class="figure"><a name="d0e565" id="d0e565"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/ogcalc.png" align=
"middle" alt="C/plain/ogcalc in action"></div>
<p class="title c3">Figure 6. <tt class=
"literal">C/plain/ogcalc</tt> in action</p>
</div>
<p>This program consists of just three functions:</p>
<p><tt class="function">on_button_clicked_reset()</tt> - Reset the
interface to its default state</p>
<p><tt class="function">on_button_clicked_calculate</tt> - Get the
values the user has entered, do a calculation, then display the
results.</p>
<p><tt class="function">main()</tt> - Initialise GTK+, construct
the interface, connect the signal handlers, then enter the GTK+
event loop.</p>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e587" id="d0e587"></a>Code
Listing</h3>
</div>
<p>The program code is listed on pages 23-26. The source code is
extensively commented, to explain what is going on.</p>
<p>To build the source, do the following:</p>
<pre class="screen">
cd C/plain
cc 'pkg-config -cflags gtk+-2.0' -c ogcalc.c
cc 'pkg-config -libs gtk+-2.0' -o ogcalc 
ogcalc.o
</pre>
<p><span class="emphasis"><em>Roger Leigh</em></span></p>
<p>[<i><span class="remark">I would recommend entering the code, it
would be a valuable exercise in learning how a GTK application is
built up. It may take a little while, but it certainly helped me to
understand what is going on. - Ed</span></i>]</p>
<pre class="programlisting">
// C/plain/ogcalc.c
#include &lt;gtk/gtk.h&gt;

GtkWidget *create_spin_entry(
          const gchar *label_text,
          const gchar *tooltip_text,
          GtkWidget **spinbutton_pointer,
          GtkAdjustment *adjustment,
          guint digits);
GtkWidget *create_result_label(
          const gchar *label_text,
          const gchar *tooltip_text,
          GtkWidget **result_label_pointer);
void on_button_clicked_reset(
          GtkWidget *widget,
          gpointer data);
void on_button_clicked_calculate(
          GtkWidget *widget,
          gpointer data);

/* This structure holds all of the widgets
   needed to get all the values for the
   calculation. */
struct calculation_widgets {
  GtkWidget *pg_val;     // PG entry widget
  GtkWidget *ri_val;     // RI entry widget
  GtkWidget *cf_val;     // CF entry widget
  GtkWidget *og_result;  // OG result label
  GtkWidget *abv_result; // ABV% result label
};

int main(int argc, char *argv[]) {
  /* These are pointers to widgets used in
     constructing the interface, and later
     used by signal handlers. */
  GtkWidget *window;
  GtkWidget *vbox1, *vbox2, *hbox1, *hbox2,
            *button1, *button2;
  GtkObject *adjustment, *hsep;
  struct calculation_widgets cb_widgets;

  gtk_init(&amp;argc, &amp;argv); // Initialise GTK+.
  
  /* Create a new top-level window. */
  window =
         gtk_window_new(GTK_WINDOW_TOPLEVEL);
  /* Set the window title. */
  gtk_window_set_title(GTK_WINDOW(window),
                       &quot;OG &amp; ABV Calculator&quot;);
  /* Disable window resizing */
  gtk_window_set_resizable(GTK_WINDOW(window),
                           FALSE);
  /* Connect the window close button
     (&quot;destroy&quot; event) to gtk_main_quit(). */
  g_signal_connect(G_OBJECT(window),
                   &quot;destroy&quot;, gtk_main_quit,
                   NULL);

  /* Create a GtkVBox to hold the other
     widgets.  This contains other widgets,
     which are packed in to it vertically. */
  vbox1 = gtk_vbox_new(FALSE, 0);
  /* Add the VBox to the Window.  A GtkWindow
    /is a/ GtkContainer which /is a/
    GtkWidget.  GTK_CONTAINER casts the
    GtkWidget to a GtkContainer, like a C++
    dynamic_cast. */
  gtk_container_add(GTK_CONTAINER(window),
                    vbox1);
  /* Display the Vbox.  At this point, the
     Window has not yet been displayed, so the
     window isn't yet visible. */
  gtk_widget_show(vbox1);

  /* Create a second GtkVBox.  Unlike the
     previous VBox, the widgets it will
     contain will be of uniform size and
     separated by a 5 pixel gap. */
  vbox2 = gtk_vbox_new(TRUE, 5);
  /* Set a 10 pixel border */
  gtk_container_set_border_width(
                   GTK_CONTAINER(vbox2), 10);
  /* Add this VBox to our first VBox. */
  gtk_box_pack_start(GTK_BOX(vbox1), vbox2,
                     FALSE, FALSE, 0);

  gtk_widget_show(vbox2);

  /* Create a GtkHBox.  This is identical to a
     GtkVBox except that the widgets pack
     horizontally, instead of vertically. */
  hbox1 = gtk_hbox_new(FALSE, 10);
  /* Add to vbox2.  The function's other
     arguments mean to expand into any extra
     space alloted to it, to fill the extra
     space and to add 0 pixels of padding
     between it and its neighbour. */
  gtk_box_pack_start(GTK_BOX(vbox2), hbox1,
                     TRUE, TRUE, 0);
  gtk_widget_show (hbox1);

  /* A GtkAdjustment is used to hold a numeric
     value: the initial value, minimum and
     maximum values, &quot;step&quot; and &quot;page&quot;
     increments and the &quot;page size&quot;.  It's
     used by spin buttons, scrollbars, sliders
     etc. */
  adjustment = gtk_adjustment_new(0.0, 0.0,
                       10000.0, 0.01, 1.0, 0);
  /* Call a helper function to create a
     GtkSpinButton entry together with a label
     and a tooltip.  The spin button is stored
     in the cb_widgets.pg_val pointer for
     later use. */
  hbox2 = create_spin_entry(&quot;PG:&quot;,
                  &quot;Present Gravity (density)&quot;,
                  &amp;cb_widgets.pg_val,
                  GTK_ADJUSTMENT(adjustment),
                  2);

  /* Pack the returned GtkHBox into the
     interface. */
  gtk_box_pack_start(GTK_BOX(hbox1), hbox2,
                     TRUE, TRUE, 0);
  gtk_widget_show(hbox2);

  /* Repeat the above for the next spin
     button. */
  adjustment = gtk_adjustment_new (0.0, 0.0,
                       10000.0, 0.01, 1.0, 0);
  hbox2 = create_spin_entry(&quot;RI:&quot;,
               &quot;Refractive Index&quot;,
               &amp;cb_widgets.ri_val,
               GTK_ADJUSTMENT(adjustment), 2);
  gtk_box_pack_start(GTK_BOX(hbox1), hbox2,
                     TRUE, TRUE, 0);
  gtk_widget_show(hbox2);

  /* Repeat again for the last spin button. */
  adjustment = gtk_adjustment_new (0.0, -50.0,
                           50.0, 0.1, 1.0, 0);
  hbox2 = create_spin_entry(&quot;CF:&quot;,
                  &quot;Correction Factor&quot;,
                  &amp;cb_widgets.cf_val,
                  GTK_ADJUSTMENT(adjustment),
                  1);
  gtk_box_pack_start(GTK_BOX(hbox1), hbox2,
                     TRUE, TRUE, 0);
  gtk_widget_show(hbox2);

  /* Now we move to the second &quot;row&quot; of the
     interface, for displaying the results. */

  /* Firstly, a new GtkHBox to pack the labels
     into. */
  hbox1 = gtk_hbox_new (TRUE, 10);
  gtk_box_pack_start(GTK_BOX(vbox2), hbox1,
                     TRUE, TRUE, 0);
  gtk_widget_show (hbox1);

  /* Create the OG result label, then pack and
     display. */
  hbox2 = create_result_label(&quot;OG:&quot;,
                 &quot;Original Gravity (density)&quot;,
                 &amp;cb_widgets.og_result);
  gtk_box_pack_start(GTK_BOX(hbox1), hbox2,
                     TRUE, TRUE, 0);
  gtk_widget_show(hbox2);

  /* Repeat as above for the second result
     value. */
  hbox2 = create_result_label(&quot;ABV %:&quot;,
                 &quot;Percent Alcohol By Volume&quot;,
                 &amp;cb_widgets.abv_result);
  gtk_box_pack_start(GTK_BOX(hbox1), hbox2,
                     TRUE, TRUE, 0);
  gtk_widget_show(hbox2);

  /* Create a horizontal separator
     (GtkHSeparator) and add it to the VBox.*/
  hsep = gtk_hseparator_new();
  gtk_box_pack_start(GTK_BOX(vbox1), hsep,
                     FALSE, FALSE, 0);
  gtk_widget_show(hsep);

  /* Create a GtkHBox to hold the bottom row
     of buttons. */
  hbox1 = gtk_hbox_new(TRUE, 5); 
  gtk_container_set_border_width(
                    GTK_CONTAINER(hbox1), 10);
  gtk_box_pack_start(GTK_BOX(vbox1), hbox1,
                     TRUE, TRUE, 0);
  gtk_widget_show(hbox1);

  /* Create the &quot;Quit&quot; button.  We use a
     &quot;stock&quot; button-commonly-used buttons that
     have a set title and icon. */
  button1 =
    gtk_button_new_from_stock(GTK_STOCK_QUIT);
  /* We connect the &quot;clicked&quot; signal to the
     gtk_main_quit() callback which will end
     the program. */
  g_signal_connect(G_OBJECT(button1),
              &quot;clicked&quot;, gtk_main_quit, NULL);
  gtk_box_pack_start(GTK_BOX(hbox1), button1,
                     TRUE, TRUE, 0);
  gtk_widget_show(button1);

  /* This button resets the interface. */
  button1 =
       gtk_button_new_with_mnemonic(&quot;_Reset&quot;);
  /* The &quot;clicked&quot; signal is connected to the
     on_button_clicked_reset() callback above,
     and our &quot;cb_widgets&quot; widget list is
     passed as the second argument, cast to a
     gpointer (void). */
  g_signal_connect(G_OBJECT(button1),
          &quot;clicked&quot;,
          G_CALLBACK(on_button_clicked_reset),
          (gpointer)&amp;cb_widgets);
  /* g_signal_connect_swapped is used to
     connect a signal from one widget to the
     handler of another.  The last argument is
     the widget that will be passed as the
     first argument of the callback.  This
     causes gtk_widget_grab_focus to switch
     the focus to the PG entry. */
  g_signal_connect_swapped(G_OBJECT(button1),
     &quot;clicked&quot;,
     G_CALLBACK(gtk_widget_grab_focus),
     (gpointer)GTK_WIDGET(cb_widgets.pg_val));
  /* This lets the default action (Enter)
     activate this widget even when the focus
     is elsewhere. This doesn't set the
     default, it just makes it possible to
     set.*/
  GTK_WIDGET_SET_FLAGS(button1,
                       GTK_CAN_DEFAULT);
  gtk_box_pack_start(GTK_BOX(hbox1), button1,
                     TRUE, TRUE, 0);
  gtk_widget_show(button1);

  /* The final button is the Calculate button.*/
  button2 =
   gtk_button_new_with_mnemonic(&quot;_Calculate&quot;);
  /* When the button is clicked, call the
     on_button_clicked_calculate() function.
     This is the same as for the Reset button.*/
  g_signal_connect(G_OBJECT(button2),
      &quot;clicked&quot;,
      G_CALLBACK(on_button_clicked_calculate),
     (gpointer)&amp;cb_widgets);
  /* Switch the focus to the Reset button when
     the button is clicked. */
  g_signal_connect_swapped(G_OBJECT(button2),
            &quot;clicked&quot;,
            G_CALLBACK(gtk_widget_grab_focus),
            (gpointer)GTK_WIDGET(button1));
  /* As before, the button can be the default.*/
  GTK_WIDGET_SET_FLAGS(button2,
                       GTK_CAN_DEFAULT);
  gtk_box_pack_start(GTK_BOX(hbox1),
                     button2, TRUE, TRUE, 0);
  /* Make this button the default.  Note the
     thicker border in the interface-this
     button is activated if you press enter in
     the CF entry field. */

  gtk_widget_grab_default(button2);
  gtk_widget_show(button2);

  /* Set up data entry focus movement.  This
     makes the interface work correctly with
     the keyboard, so that you can touch-type
     through the interface with no mouse usage
     or tabbing between the fields. */

  /* When Enter is pressed in the PG entry
     box, focus is transferred to the RI
     entry. */
  g_signal_connect_swapped(
     G_OBJECT(cb_widgets.pg_val), &quot;activate&quot;,
     G_CALLBACK(gtk_widget_grab_focus),
     (gpointer)GTK_WIDGET(cb_widgets.ri_val));
  /* RI -&gt; CF. */
  g_signal_connect_swapped(
     G_OBJECT(cb_widgets.ri_val), &quot;activate&quot;,
     G_CALLBACK(gtk_widget_grab_focus),
     (gpointer)GTK_WIDGET(cb_widgets.cf_val));
  /* When Enter is pressed in the RI field, it
     activates the Calculate button. */
  g_signal_connect_swapped(
     G_OBJECT(cb_widgets.cf_val), &quot;activate&quot;,
     G_CALLBACK(gtk_window_activate_default),
     (gpointer)GTK_WIDGET(window));

  /* The interface is complete, so finally we
     show the top-level window.  This is done
     last or else the user might see the
     interface drawing itself during the short
     time it takes to construct.  It's nicer
     this way. */
  gtk_widget_show(window);

  /* Enter the GTK Event Loop.  This is where
     all the events are caught and handled. 
     It is exited with gtk_main_quit(). */
  gtk_main();

  return 0;
}

/* A utility function for UI construction.  It constructs part of the widget tree, then returns its root. */
GtkWidget *create_spin_entry(
          const gchar *label_text,
          const gchar *tooltip_text,
          GtkWidget **spinbutton_pointer,
          GtkAdjustment *adjustment,
          guint digits) {
  GtkWidget *hbox, *eventbox, *spinbutton,
            *label;
  GtkTooltips *tooltip;

  /* A GtkHBox to pack the entry child widgets
     into. */
  hbox = gtk_hbox_new(FALSE, 5);

  /* An eventbox.  This widget is just a
     container for widgets (like labels) that
     don't have an associated X window, and so
     can't receive X events.  This is just
     used to we can add tooltips to each
     label. */
  eventbox = gtk_event_box_new();
  gtk_widget_show(eventbox);
  gtk_box_pack_start(GTK_BOX(hbox),
                    eventbox,FALSE, FALSE, 0);
  /* Create a label. */
  label = gtk_label_new(label_text);

  /* Add the label to the eventbox */
  gtk_container_add(GTK_CONTAINER(eventbox),
                    label);
  gtk_widget_show(label);

  /* Create a GtkSpinButton and associate it
     with the adjustment. It adds/substracts
     0.5 when the spin buttons are used, and
     has digits accuracy. */
  spinbutton = gtk_spin_button_new(
                adjustment, 0.5, digits);
  /* Only numbers can be entered. */
  gtk_spin_button_set_numeric(
           GTK_SPIN_BUTTON(spinbutton), TRUE);
  gtk_box_pack_start(GTK_BOX(hbox),
           spinbutton, TRUE, TRUE, 0);
  gtk_widget_show(spinbutton);

  /* Create a tooltip and add it to the
     EventBox previously created. */
  tooltip = gtk_tooltips_new();
  gtk_tooltips_set_tip(tooltip, eventbox,
                       tooltip_text, NULL);

  *spinbutton_pointer = spinbutton;
  return hbox;
}

/* A utility function for UI construction.  It
   constructs part of the widget tree, then
   returns its root. */
GtkWidget *create_result_label(
          const gchar *label_text,
          const gchar *tooltip_text,
          GtkWidget **result_label_pointer) {
  GtkWidget *hbox, *eventbox, *result_label,
            *result_value;
  GtkTooltips *tooltip;

  /*A GtkHBox to pack entry child widgets into*/
  hbox = gtk_hbox_new(FALSE, 5);

  /* As before, a label in an event box with a
     tooltip. */
  eventbox = gtk_event_box_new();
  gtk_widget_show(eventbox);
  gtk_box_pack_start(GTK_BOX(hbox), eventbox,
                     FALSE, FALSE, 0);
  result_label = gtk_label_new(label_text);
  gtk_container_add(GTK_CONTAINER(eventbox),
                    result_label);
  gtk_widget_show(result_label);

  /* This is a label, used to display the OG
     result. */
  result_value = gtk_label_new (NULL);
  /* Because it's a result, it is set
     &quot;selectable&quot;, to allow copy/paste of the
     result, but it's not modifiable. */
  gtk_label_set_selectable(
               GTK_LABEL(result_value), TRUE);
  gtk_box_pack_start(GTK_BOX(hbox),
               result_value, TRUE, TRUE, 0);
  gtk_widget_show(result_value);

  /* Add the tooltip to the event box. */
  tooltip = gtk_tooltips_new();
  gtk_tooltips_set_tip(tooltip, eventbox,
                       tooltip_text, NULL);

  *result_label_pointer = result_value;
  return hbox;
}

/* This is a callback function.  It resets
   the values of the entry widgets, and
   clears the results.  &quot;data&quot; is the
   calculation_widgets structure, which needs
   casting back to its correct type from a
   gpointer (void) type. */
void on_button_clicked_reset(
          GtkWidget *widget,
          gpointer data ) {
  /* Widgets to manipulate. */
  struct calculation_widgets *w;

  w = (struct calculation_widgets *) data;

  gtk_spin_button_set_value(
             GTK_SPIN_BUTTON(w-&gt;pg_val), 0.0);
  gtk_spin_button_set_value(
             GTK_SPIN_BUTTON(w-&gt;ri_val), 0.0);
  gtk_spin_button_set_value(
             GTK_SPIN_BUTTON(w-&gt;cf_val), 0.0);
  gtk_label_set_text(
             GTK_LABEL(w-&gt;og_result), &quot;&quot;);
  gtk_label_set_text(
             GTK_LABEL(w-&gt;abv_result), &quot;&quot;);
}

/* This callback does the actual calculation. 
   Its arguments are the same as for
   on_button_clicked_reset(). */
void on_button_clicked_calculate(
          GtkWidget *widget,
          gpointer data ) {
  gdouble pg, ri, cf, og, abv;
  gchar *og_string, *abv_string;
  struct calculation_widgets *w;

  w = (struct calculation_widgets *) data;

  /* Get the numerical values from the entry
     widgets. */
  pg = gtk_spin_button_get_value(
                  GTK_SPIN_BUTTON(w-&gt;pg_val));
  ri = gtk_spin_button_get_value(
                  GTK_SPIN_BUTTON(w-&gt;ri_val));
  cf = gtk_spin_button_get_value(
                  GTK_SPIN_BUTTON(w-&gt;cf_val));

  og = (ri*2.597) - (pg*1.644) - 34.4165 + cf;

  /* Do the sums. */
  if (og &lt; 60)
    abv = (og - pg) * 0.130;
  else
    abv = (og - pg) * 0.134;

  /* Display the results.  Note the
     &lt;b&gt;&lt;/b&gt; GMarkup tags to make it display
     in Bold. */
  og_string =
         g_strdup_printf(&quot;&lt;b&gt;%0.2f&lt;/b&gt;&quot;, og);
  abv_string =
         g_strdup_printf(&quot;&lt;b&gt;%0.2f&lt;/b&gt;&quot;, abv);

  gtk_label_set_markup(
                    GTK_LABEL(w-&gt;og_result),
                    og_string);
  gtk_label_set_markup(
                    GTK_LABEL(w-&gt;abv_result),
                    abv_string);

  g_free(og_string);
  g_free(abv_string);
}
</pre></div>
</div>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
