    <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 - Part
2</title>
        <link>https://members.accu.org/index.php/articles/692</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, #5 - Oct 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/c100/">165</a>
<br />

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

                    -                        <a href="https://members.accu.org/index.php/articles/c65+100/">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 - Part
2</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 03 October 2004 13:16:07 +01:00 or Sun, 03 October 2004 13:16:07 +01:00</p>
<p><strong>Summary:</strong>&nbsp;<p>In this part, I will be showing how to use the Glade application for rapid window creation.</p></p>
<p><strong>Body:</strong>&nbsp;<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e20" id="d0e20"></a>Last
Time...</h2>
</div>
<p>As you will recall from the first part, I showed how to
construct a GTK window with all of its associated parts in some
detail, and it was clear that to do this for every application
would not be a good idea. In this part, I will be showing how to
use the Glade application for rapid window creation.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e25" id="d0e25"></a>Analysis</h2>
</div>
<p>The <tt class="function">main()</tt> function is responsible for
constructing the user interface, connecting the signals to the
signal handlers, and then entering the main event loop. The more
complex aspects of the function are discussed here.</p>
<pre class="programlisting">
g_signal_connect(G_OBJECT(window), &quot;destroy&quot;,
                 gtk_main_quit, NULL);
</pre>
<p>This code connects the &quot;<tt class="literal">destroy</tt>&quot; signal
to the <tt class="function">gtk_main_quit()</tt> function. This
signal is emitted by the window if is to be destroyed, for example
when the &quot;close&quot; button on the titlebar is clicked). The result is
that when the window is closed, the main event loop returns, and
the program then exits.</p>
<pre class="programlisting">
vbox1 = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox1);
</pre>
<p><tt class="varname">vbox1</tt> is a <tt class=
"classname">GtkVBox</tt>. When constructed using <tt class=
"function">gtk_vbox_new()</tt>, it is set to be non-homogenous
(<tt class="literal">FALSE</tt>), which allows the widgets
contained within the <tt class="classname">GtkVBox</tt> to be of
different sizes, and has zero pixels padding space between the
containers it contains. The homogeneity and padding space are
different for the various <tt class="classname">GtkBox</tt>es used,
depending on the visual effect intended. <tt class=
"function">gtk_container_add()</tt> packs <tt class=
"varname">vbox1</tt> into the window (a <tt class=
"classname">GtkWindow</tt> object is a <tt class=
"classname">GtkContainer</tt>).</p>
<pre class="programlisting">
eventbox = gtk_event_box_new();
gtk_widget_show(eventbox);
gtk_box_pack_start(GTK_BOX(hbox2), eventbox,
                   FALSE, FALSE, 0);
</pre>
<p>Some widgets do not receive events from the windowing system,
and hence cannot emit signals. Label widgets are one example of
this. If this is required, for example in order to show a tooltip,
they must be put into a <tt class="classname">GtkEventBox</tt>,
which can receive the events. The signals emitted from the
<tt class="classname">GtkEventBox</tt> may then be connected to the
appropriate handler.</p>
<p><tt class="function">gtk_widget_show()</tt> displays a widget.
Widgets are hidden by default when created, and so must be shown
before they can be used.</p>
<p>It is typical to show the top-level window last, so that the
user does not see the interface being drawn.</p>
<p><tt class="function">gtk_box_pack_start()</tt> packs a widget
into a <tt class="classname">GtkBox</tt>, in a similar manner to
<tt class="function">gtk_container_add()</tt>. This packs
<tt class="varname">eventbox</tt> into <tt class=
"varname">hbox2</tt>. The last three arguments control whether the
child widget should expand into any extra space available, whether
it should fill any extra space available (this has no effect if
expand is <tt class="literal">FALSE</tt>), and extra space in
pixels to put between its neighbours (or the edge of the box),
respectively. Figure 1 shows how <tt class=
"function">gtk_box_pack_start()</tt> works.</p>
<div class="figure"><a name="d0e114" id="d0e114"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig1.png"
align="middle" alt="gtk_box_pack_start()"></div>
<p class="title c3">Figure 1. gtk_box_pack_start()</p>
</div>
<p>The <tt class="function">create_spin_entry()</tt> function is a
helper function to create a numeric entry (spin button) together
with a label and tooltip. It is used to create all three
entries.</p>
<pre class="programlisting">
label = gtk_label_new(label_text);
</pre>
<p>A new label is created displaying the text label_text.</p>
<pre class="programlisting">
spinbutton = gtk_spin_button_new(adjustment,
                                 0.5, 2);
gtk_spin_button_set_numeric(
           GTK_SPIN_BUTTON(spinbutton), TRUE);
</pre>
<p>A <tt class="classname">GtkSpinButton</tt> is a numeric entry
field. It has up and down buttons to &quot;spin&quot; the numeric value up
and down. It is associated with a <tt class=
"classname">GtkAdjustment</tt>, which controls the range allowed,
default value, etc. <tt class="function">gtk_adjustment_new()</tt>
returns a new <tt class="classname">GtkAdjustment</tt> object. Its
arguments are the default value, minimum value, maximum value, step
increment, page increment and page size, respectively. This is
straightforward, apart from the step and page increments and sizes.
The step and page increments are the value that will be added or
subtracted when the mouse button 1 or button 2 are clicked on the
up or down buttons, respectively. The page size has no meaning in
this context (<tt class="classname">GtkAdjustment</tt>s are also
used with scrollbars).</p>
<p><tt class="function">gtk_spin_button_new()</tt> creates a new
<tt class="classname">GtkSpinButton</tt>, and associates it with
adjustment. The second and third arguments set the &quot;climb rate&quot;
(rate of change when the spin buttons are pressed) and the number
of decimal places to display.</p>
<p>Finally, <tt class="function">gtk_spin_button_set_numeric()</tt>
is used to ensure that only numbers can be entered.</p>
<pre class="programlisting">
tooltip = gtk_tooltips_new();
gtk_tooltips_set_tip(tooltip, eventbox,
                     tooltip_text, NULL);
</pre>
<p>A tooltip (pop-up help message) is created with <tt class=
"function">gtk_tooltips_new()</tt>. <tt class=
"function">gtk_tooltips_set_tip()</tt> is used to associate tooltip
with the eventbox widget, also specifying the message it should
contain. The fourth argument should typically be <tt class=
"literal">NULL</tt>.</p>
<p>The <tt class="function">create_result_label()</tt> function is
a helper function to create a result label together with a
descriptive label and tooltip.</p>
<pre class="programlisting">
gtk_label_set_selectable(
               GTK_LABEL(result_value), TRUE);
</pre>
<p>Normally, labels simply display a text string. The above code
allows the text to be selected and copied, to allow pasting of the
text elsewhere. This is used for the result fields so the user can
easily copy them.</p>
<pre class="programlisting">
button1
  = gtk_button_new_from_stock(GTK_STOCK_QUIT);
</pre>
<p>This code creates a new button, using a stock widget. A stock
widget contains a predefined icon and text. These are available for
commonly used functions, such as &quot;OK&quot;, &quot;Cancel&quot;, &quot;Print&quot;, etc..</p>
<pre class="programlisting">
button2 = gtk_button_new_with_mnemonic(
                                &quot;_Calculate&quot;);
g_signal_connect(G_OBJECT (button2),
      &quot;clicked&quot;,
      G_CALLBACK(on_button_clicked_calculate),
      (gpointer) &amp;cb_widgets);
GTK_WIDGET_SET_FLAGS(button2,
                     GTK_CAN_DEFAULT);
</pre>
<p>Here, a button is created, with the label &quot;Calculate&quot;. The
mnemonic is the &quot;<tt class="literal">_C</tt>&quot;, which creates an
accelerator. This means that when Alt-C is pressed, the button is
activated (i.e. it is a keyboard shortcut). The shortcut is
underlined, in common with other graphical toolkits.</p>
<p>The &quot;clicked&quot; signal (emitted when the button is pressed and
released) is connected to the <tt class=
"function">on_button_clicked_calculate()</tt> callback. The
<span class="structname">cb_widgets</span> structure is passed as
the argument to the callback.</p>
<p>Lastly, the <i class="structfield"><tt>GTK_CAN_DEFAULT</tt></i>
attribute is set. This attribute allows the button to be the
default widget in the window.</p>
<pre class="programlisting">
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));
</pre>
<p>This code connects signals in the same way as <tt class=
"function">gtk_signal_connect()</tt>. The difference is the fourth
argument, which is a <tt class="classname">GtkWidget</tt> pointer.
This allows the signal emitted by one widget to be received by the
signal handler for another. Basically, the widget argument of the
signal handler is given <i class=
"structfield"><tt>cb_widgets.ri_val</tt></i> rather than <i class=
"structfield"><tt>cb_widgets.pg_val</tt></i>. This allows the focus
(where keyboard input is sent) to be switched to the next entry
field when Enter is pressed in the first.</p>
<pre class="programlisting">
g_signal_connect_swapped
  (G_OBJECT(cb_widgets.cf_val), &quot;activate&quot;,
      G_CALLBACK(gtk_window_activate_default),
      (gpointer)GTK_WIDGET(window));
</pre>
<p>This is identical to the last example, but in this case the
callback is the function <tt class=
"function">gtk_window_activate_default()</tt> and the widget to
give to the signal handler is window. When Enter is pressed in the
CF entry field, the default &quot;Calculate&quot; button is activated.</p>
<pre class="programlisting">
gtk_main();
</pre>
<p>This is the GTK+ event loop. It runs until <tt class=
"function">gtk_main_quit()</tt> is called.</p>
<p>The signal handlers are far simpler than building the interface.
The <tt class="function">function
on_button_clicked_calculate()</tt> reads the user input, performs a
calculation, then displays the result.</p>
<pre class="programlisting">
void on_button_clicked_calculate(
                            GtkWidget *widget,
                            gpointer data) {
  struct calculation_widgets *w;
  w = (struct calculation_widgets *) data;
</pre>
<p>Recall that a pointer to <span class=
"structname">cb_widgets</span>, of type <tt class="type">struct
calculation_widgets</tt>, was passed to the signal handler, cast to
a <tt class="type">gpointer</tt>. The reverse process is now
applied, casting <tt class="varname">data</tt> to a pointer of type
<tt class="type">struct calculation_widgets</tt>.</p>
<pre class="programlisting">
gdouble pg;
pg = gtk_spin_button_get_value(
                  GTK_SPIN_BUTTON(w-&gt;pg_val));
</pre>
<p>This code gets the value from the <tt class=
"classname">GtkSpinButton</tt>.</p>
<pre class="programlisting">
gchar *og_string;
og_string = g_strdup_printf(&quot;&lt;b&gt;%0.2f&lt;/b&gt;&quot;, og);
gtk_label_set_markup(GTK_LABEL(w-&gt;og_result),
                     og_string);
g_free(og_string);
</pre>
<p>Here the result <tt class="varname">og</tt> is printed to the
string <tt class="varname">og_string</tt>. This is then set as the
label text using <tt class="function">gtk_label_set_markup()</tt>.
This function sets the label text using the Pango Markup Format,
which uses the <tt class="literal">&lt;b&gt;</tt> and <tt class=
"literal">&lt;/b&gt;</tt> tags to embolden the text.</p>
<pre class="programlisting">
gtk_spin_button_set_value(
             GTK_SPIN_BUTTON(w-&gt;pg_val), 0.0);
gtk_label_set_text(
             GTK_LABEL(w-&gt;og_result), &quot;&quot;);
</pre>
<p><tt class="function">on_button_clicked_reset()</tt> resets the
input fields to their default value, and blanks the result
fields.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e292" id="d0e292"></a>GTK+ and
Glade</h2>
</div>
<div class="sect2" lang="en">
<div class="titlepage">
<h3><a name="d0e295" id=
"d0e295"></a>Introduction</h3>
</div>
<p>In the previous section, the user interface was constructed
entirely &quot;by hand&quot;. This might seem to be rather difficult to do,
as well as being messy and time-consuming. In addition, it also
makes for rather unmaintainable code, since changing the interface,
for example to add a new feature, would be rather hard. As
interfaces become more complex, constructing them entirely in code
becomes less feasible.</p>
<p>The Glade user interface designer is an alternative to this.
Glade allows one to design an interface visually, selecting the
desired widgets from a palette and placing them on windows, or in
containers, in a similar manner to other interface designers.
Figures 3-7 (see next page) shows some screenshots of the various
components of Glade.</p>
<p>The file <tt class="filename">C/glade/ogcalc.glade</tt> contains
the same interface constructed in <tt class=
"filename">C/plain/ogcalc.c</tt>, but designed in Glade. This file
can be opened in Glade, and changed as needed, without needing to
touch any code.</p>
<p>Even signal connection is automated. Examine the &quot;Signals&quot; tab
in the &quot;Properties&quot; dialog box.</p>
<p>The source code is listed below. This is the same as the
previous listing, but with the following changes:</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>The <tt class="function">main()</tt> function does not construct
the interface. It merely loads the <tt class=
"filename">ogcalc.glade</tt> interface description, auto-connects
the signals, and shows the main window.</p>
</li>
<li>
<p>The <span class="structname">cb_widgets</span> structure is no
longer needed: the callbacks are now able to query the widget tree
through the Glade XML object to locate the widgets they need. This
allows for greater encapsulation of data, and signal handler
connection is simpler.</p>
</li>
<li>
<p>The code saving is significant, and there is now separation
between the interface and the callbacks.</p>
</li>
</ul>
</div>
<p>The running <tt class="filename">C/glade/ogcalc</tt> application
is shown in Figure 2. Notice that it is identical to <tt class=
"filename">C/plain/ogcalc</tt>, shown in the last article. (No,
they are not the same screenshot!)</p>
</div>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e341" id="d0e341"></a>Analysis</h2>
</div>
<div class="figure"><a name="d0e344" id="d0e344"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig2.png"
align="middle" alt="C/glade/ogcalc in action"></div>
<p class="title c3">Figure 2. <tt class=
"filename">C/glade/ogcalc</tt> in action</p>
</div>
<p>The most obvious difference between the code using Glade (see
listing at end of article) and the previous code is the huge
reduction in size. The <tt class="function">main()</tt> function is
reduced to just these lines:</p>
<pre class="programlisting">
GladeXML *xml;
GtkWidget *window;

xml = glade_xml_new(&quot;ogcalc.glade&quot;, NULL, NULL);

glade_xml_signal_autoconnect(xml);

window = glade_xml_get_widget(xml,
                        &quot;ogcalc_main_window&quot;);
gtk_widget_show(window);
</pre>
<p><tt class="function">glade_xml_new()</tt> reads the interface
from the file <tt class="filename">ogcalc.glade</tt>. It returns
the interface as a pointer to a GladeXML object, which will be used
later. Next, the signal handlers are connected with <tt class=
"function">glade_xml_signal_autoconnect()</tt>. Windows users may
require special linker flags because signal autoconnection requires
the executable to have a dynamic symbol table in order to
dynamically find the required functions.</p>
<p>The signal handlers are identical to those in the previous
section. The only difference is that struct <span class=
"structname">calculation_widgets</span> has been removed. No
information needs to be passed to them through the data argument,
since the widgets they need to use may now be found using the
GladeXML interface description.</p>
<pre class="programlisting">
GtkWidget *pg_val;
GladeXML *xml;
xml = glade_get_widget_tree(
                         GTK_WIDGET (widget));
pg_val = glade_xml_get_widget(xml, &quot;pg_entry&quot;);
</pre>
<p>Firstly, the GladeXML interface is found, by finding the widget
tree containing the widget passed as the first argument to the
signal handler. Once xml has been set, <tt class=
"function">glade_xml_get_widget()</tt> may be used to obtain
pointers to the <tt class="classname">GtkWidget</tt>s stored in the
widget tree.</p>
<p>Compared with the pure C GTK+ application, the code is far
simpler, and the signal handlers no longer need to get their data
as structures cast to gpointer, which was ugly. The code is far
more understandable, cleaner and maintainable.</p>
<div class="figure"><a name="d0e386" id="d0e386"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig3a.png"
align="middle" alt=
"The Glade user interface designer: The Opening window"></div>
<p class="title c3">Figure 3. The Glade user interface designer:
The Opening window</p>
</div>
<div class="figure"><a name="d0e392" id="d0e392"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig3b.png"
align="middle" alt=
"The Glade user interface designer: The palette tree"></div>
<p class="title c3">Figure 4. The Glade user interface designer:
The palette tree</p>
</div>
<div class="figure"><a name="d0e398" id="d0e398"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig3c.png"
align="middle" alt=
"The Glade user interface designer: The widget properties dialog"></div>
<p class="title c3">Figure 5. The Glade user interface designer:
The widget properties dialog</p>
</div>
<div class="figure"><a name="d0e404" id="d0e404"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig3d.png"
align="middle" alt=
"The Glade user interface designer: The widget tree"></div>
<p class="title c3">Figure 6. The Glade user interface designer:
The widget tree</p>
</div>
<div class="figure"><a name="d0e410" id="d0e410"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/leigh-fig3e.png"
align="middle" alt=
"The Glade user interface designer: The program being designed"></div>
<p class="title c3">Figure 7. The Glade user interface designer:
The program being designed</p>
</div>
<p><span class="bold"><b>Listing: C/glade/ogcalc.c</b></span></p>
<pre class="programlisting">
#include &lt;gtk/gtk.h&gt;
#include &lt;glade/glade.h&gt;

void on_button_clicked_reset(GtkWidget *widget,
                             gpointer data);
void on_button_clicked_calculate(GtkWidget *widget,
                                 gpointer data);

/* The bulk of the program.  Since Glade and
   libglade are used, this is just 9 lines! */
int main(int argc, char *argv[]) {
  GladeXML *xml;
  GtkWidget *window;

  /* Initialise GTK+. */
  gtk_init(&amp;argc, &amp;argv);

  /* Load the interface description. */
  xml = glade_xml_new(&quot;ogcalc.glade&quot;, NULL, NULL);

  /* Set up the signal handlers. */
  glade_xml_signal_autoconnect(xml);

  /* Find the main window and then show it. */
  window = glade_xml_get_widget(xml,
                              &quot;ogcalc_main_window&quot;);
  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;
}

/* This is a callback.  This resets the values of
   the entry widgets, and clears the results. */
void on_button_clicked_reset(GtkWidget *widget,
                             gpointer data) {
  GtkWidget *pg_val;
  GtkWidget *ri_val;
  GtkWidget *cf_val;
  GtkWidget *og_result;
  GtkWidget *abv_result;

  GladeXML *xml;

  /* Find the Glade XML tree containing widget. */
  xml = glade_get_widget_tree(GTK_WIDGET (widget));

  /* Pull the other widgets out the the tree. */
  pg_val = glade_xml_get_widget(xml,
                                   &quot;pg_entry&quot;);
  ri_val = glade_xml_get_widget(xml,
                                   &quot;ri_entry&quot;);
  cf_val = glade_xml_get_widget(xml,
                                   &quot;cf_entry&quot;);
  og_result = glade_xml_get_widget(xml,
                                   &quot;og_result&quot;);
  abv_result = glade_xml_get_widget(xml,
                                   &quot;abv_result&quot;);

  gtk_spin_button_set_value(GTK_SPIN_BUTTON(pg_val),
                            0.0);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(ri_val),
                            0.0);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(cf_val),
                            0.0);
  gtk_label_set_text(GTK_LABEL(og_result), &quot;&quot;);
  gtk_label_set_text(GTK_LABEL(abv_result), &quot;&quot;);
}


/* This callback does the actual calculation. */
void on_button_clicked_calculate(GtkWidget *widget,
                                 gpointer data) {
  GtkWidget *pg_val;
  GtkWidget *ri_val;
  GtkWidget *cf_val;
  GtkWidget *og_result;
  GtkWidget *abv_result;

  GladeXML *xml;

  gdouble pg, ri, cf, og, abv;
  gchar *og_string;
  gchar *abv_string;

  /* Find the Glade XML tree containing widget. */
  xml = glade_get_widget_tree(GTK_WIDGET(widget));

  /* Pull the other widgets out the the tree. */
  pg_val = glade_xml_get_widget(xml,
                                   &quot;pg_entry&quot;);
  ri_val = glade_xml_get_widget(xml,
                                   &quot;ri_entry&quot;);
  cf_val = glade_xml_get_widget(xml,
                                   &quot;cf_entry&quot;);
  og_result = glade_xml_get_widget(xml,
                                   &quot;og_result&quot;);
  abv_result = glade_xml_get_widget(xml,
                                   &quot;abv_result&quot;);

  /* Get the numerical values from the entry
     widgets. */
  pg = gtk_spin_button_get_value(
                          GTK_SPIN_BUTTON(pg_val));
  ri = gtk_spin_button_get_value(
                          GTK_SPIN_BUTTON(ri_val));
  cf = gtk_spin_button_get_value(
                          GTK_SPIN_BUTTON(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(og_result),
                       og_string);
  gtk_label_set_markup(GTK_LABEL(abv_result),
                       abv_string);

  g_free(og_string);
  g_free(abv_string);
}
</pre>
<p>To build the source, do the following:</p>
<pre class="screen">
cd C/glade
cc 'pkg-config --cflags libglade-2.0' -c ogcalc.c
cc 'pkg-config --libs libglade-2.0' -o ogcalc ogcalc.o
</pre></div>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
