Alternative form of examples

This section provides alternative implementations for some of the GTK examples. It demonstrates how to use connection methods that are suboptimal yet are still in use. It is not suggested that these methods be used, but rather that these examples are used when needed to understand other code that already exists.

Libglade autoconnection and example-1

The file using the C language bindings to GTK making use of libglade autoconnection to make the interface layout from example-1 into a functioning program is below.

/* This program displays a simple window and has a simple callback for
 * when the OK button is clicked.
 */

#include <gtk/gtk.h>
#include <glade/glade.h>

void
ok_button_clicked (GtkWidget *widget, gpointer user_data)
{
  printf ("Thanks for trying out my program.\n");
  gtk_main_quit ();
}

int
main (int argc, char *argv[])
{
  GladeXML *main_window;

  gtk_init (&argc, &argv);

  /* load the interface */
  main_window = glade_xml_new ("example-1.glade", NULL, NULL);

  /* connect the signals in the interface */
  glade_xml_signal_autoconnect (main_window);

  /* start the event loop */
  gtk_main ();

  return 0;
}

Libglade manual connection and example-2

The file using the C language bindings to GTK making use of libglade manual connection to make the interface layout from example-2 into a functioning program is below.

/* This program displays a "pulsing" (or whatever it's called)
 * ProgressBar, adds a timeout function to keep it updated, shows how
 * to obtain an individual widget that libglade created, and also
 * manually sets up the callback for the delete_event on the main
 * window so that some data (a glib timer) can be attached to the
 * callback.
 *
 * Note that most programs update progress bars during some kind of
 * function that doesn't return to the main event loop (unlike this
 * simple example).  In that case, you must manually tell gtk to
 * update widgets yourself by calling g_main_context_iteration.  (See
 * example-3.c for an example of doing this in a different context).
 */

#include <gtk/gtk.h>
#include <glib.h>
#include <glade/glade.h>

/* This is the callback for the delete_event, i.e. window closing */
void
inform_user_of_time_wasted (GtkWidget *widget, GdkEvent * event, gpointer data)
{
  /* Get the elapsed time since the timer was started */
  GTimer * timer = (GTimer*) data;
  gulong dumb_API_needs_this_variable;
  gdouble time_elapsed = g_timer_elapsed (timer, &dumb_API_needs_this_variable);

  /* Tell the user how much time they used */
  printf ("You wasted %.2f seconds with this program.\n", time_elapsed);

  /* Free the memory from the timer */
  g_timer_destroy (timer);

  /* Make the main event loop quit */
  gtk_main_quit ();
}

gboolean
update_progress_bar (gpointer data)
{
  gtk_progress_bar_pulse (GTK_PROGRESS_BAR (data));

  /* Return true so the function will be called again; returning false removes
   * this timeout function.
   */
  return TRUE;
}

int
main (int argc, char *argv[])
{
  GladeXML *what_a_waste;

  gtk_init (&argc, &argv);

  /* load the interface, but don't call glade_xml_signal_autoconnect
   * since we want to connect data to the callbacks--meaning that we
   * have to manually connect callbacks.
   */
  what_a_waste = glade_xml_new ("example-2.glade", NULL, NULL);

  /* Get the progress bar widget and change it to "activity mode", i.e. a block
   * that bounces back and forth instead of a normal progress bar that fills
   * to completion.
   */
  GtkWidget *progress_bar = glade_xml_get_widget (what_a_waste, "Progress Bar");
  gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar));

  /* Add a timeout to update the progress bar every 100 milliseconds or so */
  gint func_ref = g_timeout_add (100, update_progress_bar, progress_bar);

  /* Start the wasted_time_tracker timer, and connect it to the callback */
  GTimer *wasted_time_tracker = g_timer_new ();
  glade_xml_signal_connect_data (what_a_waste,
                                 "inform_user_of_time_wasted",
                                 G_CALLBACK (inform_user_of_time_wasted),
                                 wasted_time_tracker);

  /* start the event loop */
  gtk_main ();

  /* Remove the timeout function--not that it matters since we're about to end */
  g_source_remove (func_ref);

  return 0;
}

Libglade autoconnection and example-3

The file using the C language bindings to GTK making use of libglade autoconnection to make the interface layout from example-3 into a functioning program is below.

/* This program displays a couple checkboxes and shows how to change
 * button labels, how to make widgets sensitive or unsensitive, how to
 * determine if a checkbox is active, how to provide access keys for
 * quick keyboard navigation, how to pass other widgets to callbacks
 * besides the one that receives the event, and how to manually get
 * gtk+ to update widgets without returning to the main event loop.
 */

#include <gtk/gtk.h>
#include <glade/glade.h>

/* Libglade uses G_CONNECT_SWAPPED when an Object is specified for a
 * signal handler which causes the parameters to be swapped.  This
 * means that the widget that receives the event (where in this case
 * the event is a click) is the second parameter instead of the first,
 * while the first parameter is the Object specified in the xml file.
 */
void
quit_handler (gpointer user_data, GtkWidget *widget)
{
  /* If the user checked the OohTellMe button, we need to do some work... */
  GtkWidget * ooh_tell_me = (GtkWidget*) user_data;
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ooh_tell_me)))
    {
      /* Change the checkbutton's label */
      gtk_button_set_label (GTK_BUTTON (ooh_tell_me),
                            "M_ock me");

      /* Since we don't return to the main event loop, we have to manually tell
       * gtk+ to process the gtk_button_set_label change (and any other changes
       * that require processing).
       */
      while (g_main_context_iteration (NULL, FALSE))
        ;

      /* Mock the user and give them some time to notice the change */
      printf ("Ha ha, you fell for it!  ");
      printf ("I will not tell you what that checkbutton does!\n");
      sleep (1);
    }

  gtk_main_quit ();
}

/* Libglade uses G_CONNECT_SWAPPED when an Object is specified for a
 * signal handler which causes the parameters to be swapped.  This
 * means that the widget that receives the event (where in this case
 * the event is a click) is the second parameter instead of the first,
 * while the first parameter is the Object specified in the xml file.
 */
gboolean
delete_handler (gpointer user_data, GdkEvent *event, GtkWidget *widget)
{
  quit_handler(user_data, widget);

  /* We have fully handled the signal */
  return TRUE;
}

/* Libglade uses G_CONNECT_SWAPPED when an Object is specified for a
 * signal handler which causes the parameters to be swapped.  This
 * means that the widget that receives the event (where in the case
 * the event is toggling caused by a click) is the second parameter
 * instead of the first, while the first parameter is the Object
 * specified in the xml file.
 */
void
sensitivity_toggled (gpointer user_data, GtkWidget *widget)
{
  gtk_widget_set_sensitive ((GtkWidget*) user_data, 
                            gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
}

int
main (int argc, char *argv[])
{
  GladeXML *main_window;

  gtk_init (&argc, &argv);

  /* load the interface */
  main_window = glade_xml_new ("example-3.glade", NULL, NULL);

  /* connect the signals in the interface */
  glade_xml_signal_autoconnect (main_window);

  /* start the event loop */
  gtk_main ();

  return 0;
}