Example 2

An example that shows how to monitor and set a couple Nautilus preferences is shown below.

The XML file generated by glade that contains this layout is below. The code turn this graphical layout into a functioning program is shown below the .glade file.

<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">

<glade-interface>
<requires lib="gnome"/>

<widget class="GtkWindow" id="MainWindow">
  <property name="visible">True</property>
  <property name="title" translatable="yes">Nautilus Preferences</property>
  <property name="type">GTK_WINDOW_TOPLEVEL</property>
  <property name="window_position">GTK_WIN_POS_NONE</property>
  <property name="modal">False</property>
  <property name="resizable">True</property>
  <property name="destroy_with_parent">False</property>

  <child>
    <widget class="GtkVBox" id="vbox1">
      <property name="border_width">6</property>
      <property name="visible">True</property>
      <property name="homogeneous">False</property>
      <property name="spacing">0</property>

      <child>
	<widget class="GtkTable" id="table1">
	  <property name="visible">True</property>
	  <property name="n_rows">3</property>
	  <property name="n_columns">2</property>
	  <property name="homogeneous">False</property>
	  <property name="row_spacing">6</property>
	  <property name="column_spacing">0</property>

	  <child>
	    <widget class="GtkLabel" id="ShowThumbnailsLabel">
	      <property name="visible">True</property>
	      <property name="label" translatable="yes">Show Image Thumnails:</property>
	      <property name="use_underline">False</property>
	      <property name="use_markup">False</property>
	      <property name="justify">GTK_JUSTIFY_LEFT</property>
	      <property name="wrap">False</property>
	      <property name="selectable">False</property>
	      <property name="xalign">0</property>
	      <property name="yalign">0.5</property>
	      <property name="xpad">0</property>
	      <property name="ypad">0</property>
	    </widget>
	    <packing>
	      <property name="left_attach">0</property>
	      <property name="right_attach">1</property>
	      <property name="top_attach">1</property>
	      <property name="bottom_attach">2</property>
	      <property name="x_options">fill</property>
	      <property name="y_options"></property>
	    </packing>
	  </child>

	  <child>
	    <widget class="GtkLabel" id="ThumbnailLimitLabel">
	      <property name="visible">True</property>
	      <property name="label" translatable="yes">Thumbnail Size Limit:</property>
	      <property name="use_underline">False</property>
	      <property name="use_markup">False</property>
	      <property name="justify">GTK_JUSTIFY_LEFT</property>
	      <property name="wrap">False</property>
	      <property name="selectable">False</property>
	      <property name="xalign">0</property>
	      <property name="yalign">0.5</property>
	      <property name="xpad">0</property>
	      <property name="ypad">0</property>
	    </widget>
	    <packing>
	      <property name="left_attach">0</property>
	      <property name="right_attach">1</property>
	      <property name="top_attach">2</property>
	      <property name="bottom_attach">3</property>
	      <property name="x_options">fill</property>
	      <property name="y_options"></property>
	    </packing>
	  </child>

	  <child>
	    <widget class="GtkEntry" id="ShowThumbnailsEntry">
	      <property name="visible">True</property>
	      <property name="tooltip" translatable="yes">When to show thumbnails, &quot;never&quot;, &quot;local_only&quot;, or &quot;always&quot;</property>
	      <property name="can_focus">True</property>
	      <property name="editable">True</property>
	      <property name="visibility">True</property>
	      <property name="max_length">0</property>
	      <property name="text" translatable="yes"></property>
	      <property name="has_frame">True</property>
	      <property name="invisible_char" translatable="yes">*</property>
	      <property name="activates_default">False</property>
	    </widget>
	    <packing>
	      <property name="left_attach">1</property>
	      <property name="right_attach">2</property>
	      <property name="top_attach">1</property>
	      <property name="bottom_attach">2</property>
	      <property name="y_options"></property>
	    </packing>
	  </child>

	  <child>
	    <widget class="GtkEntry" id="ThumbnailLimitEntry">
	      <property name="visible">True</property>
	      <property name="tooltip" translatable="yes">Largest picture size (in bytes) that will be thumbnailed</property>
	      <property name="can_focus">True</property>
	      <property name="editable">True</property>
	      <property name="visibility">True</property>
	      <property name="max_length">0</property>
	      <property name="text" translatable="yes"></property>
	      <property name="has_frame">True</property>
	      <property name="invisible_char" translatable="yes">*</property>
	      <property name="activates_default">False</property>
	    </widget>
	    <packing>
	      <property name="left_attach">1</property>
	      <property name="right_attach">2</property>
	      <property name="top_attach">2</property>
	      <property name="bottom_attach">3</property>
	      <property name="y_options"></property>
	    </packing>
	  </child>

	  <child>
	    <widget class="GtkCheckButton" id="BrowserMode">
	      <property name="visible">True</property>
	      <property name="tooltip" translatable="yes">Whether to use the old Browser mode, or the newer &quot;each directory in a separate window&quot; spatilus mode</property>
	      <property name="can_focus">True</property>
	      <property name="label" translatable="yes">Always use _browser mode</property>
	      <property name="use_underline">True</property>
	      <property name="relief">GTK_RELIEF_NORMAL</property>
	      <property name="active">False</property>
	      <property name="inconsistent">False</property>
	      <property name="draw_indicator">True</property>
	    </widget>
	    <packing>
	      <property name="left_attach">0</property>
	      <property name="right_attach">2</property>
	      <property name="top_attach">0</property>
	      <property name="bottom_attach">1</property>
	      <property name="x_options">fill</property>
	      <property name="y_options"></property>
	    </packing>
	  </child>
	</widget>
	<packing>
	  <property name="padding">0</property>
	  <property name="expand">True</property>
	  <property name="fill">True</property>
	</packing>
      </child>

      <child>
	<widget class="GtkHSeparator" id="hseparator1">
	  <property name="visible">True</property>
	</widget>
	<packing>
	  <property name="padding">7</property>
	  <property name="expand">False</property>
	  <property name="fill">False</property>
	</packing>
      </child>

      <child>
	<widget class="GtkHButtonBox" id="hbuttonbox1">
	  <property name="visible">True</property>
	  <property name="layout_style">GTK_BUTTONBOX_END</property>
	  <property name="spacing">0</property>

	  <child>
	    <widget class="GtkButton" id="CloseButton">
	      <property name="visible">True</property>
	      <property name="can_default">True</property>
	      <property name="can_focus">True</property>
	      <property name="label">gtk-close</property>
	      <property name="use_stock">True</property>
	      <property name="relief">GTK_RELIEF_NORMAL</property>
	    </widget>
	  </child>
	</widget>
	<packing>
	  <property name="padding">0</property>
	  <property name="expand">False</property>
	  <property name="fill">False</property>
	</packing>
      </child>
    </widget>
  </child>
</widget>

</glade-interface>

GTK

The file using the C language bindings to GTK to make this interface layout into a functioning program is below.

/* This program monitors the
 * /apps/nautilus/preferences/always_use_browser,
 * /apps/nautilus/preferences/show_image_thumbnails, and
 * /apps/nautilus/preferences/thumbnail_limit gconf keys, and allows
 * the user to change them as well.
 */

#include <gtk/gtk.h>
#include <glade/glade.h>
#include <gconf/gconf-client.h>

static gboolean old_browser_setting;
static gchar*   old_show_thumbnails_setting;
static gint     old_thumbnail_limit;

/*********** callbacks for always_use_browser **********/
void
gconf_browser_key_callback (GConfClient* client,
                            guint cnxn_id,
                            GConfEntry* entry,
                            gpointer user_data)
{
  GtkWidget* button;
  button = GTK_WIDGET (user_data);

  /* Make sure the preference has a valid value */
  if (gconf_entry_get_value (entry) != NULL && 
      gconf_entry_get_value (entry)->type == GCONF_VALUE_BOOL)
    {
      /* Get the new value */
      gboolean new_browser_setting =
        gconf_value_get_bool (gconf_entry_get_value (entry));

      /* Try to handle asynchronous-ness of GConf and prevent calling
       * browser_key_toggled_callback again if this function was
       * called as a result of the gconf_client_set_bool function
       * call.
       */
      if (new_browser_setting != old_browser_setting)
        {
          old_browser_setting = new_browser_setting;
          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
                                        new_browser_setting);
        }
    }
}

void
browser_key_toggled_callback (GtkWidget* check_button, gpointer user_data)
{
  GConfClient* client = GCONF_CLIENT (user_data);

  /* Determine whether the checkbutton is already set or not */
  gboolean is_set = 
    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_button));
 
  /* Try to handle asynchronous-ness of GConf and prevent calling
   * gconf_browser_key_callback again if this function was called as a
   * result of the gtk_toggle_button_set_active function call.
   */
  if (is_set != old_browser_setting)
    {
      old_browser_setting = is_set;
      gconf_client_set_bool (client,
                             "/apps/nautilus/preferences/always_use_browser",
                             is_set,
                             NULL);
    }
}

/*********** callbacks for show_image_thumbnails **********/
void
gconf_show_thumbnails_callback (GConfClient* client,
                                guint cnxn_id,
                                GConfEntry* entry,
                                gpointer user_data)
{
  GtkWidget* show_entry;
  show_entry = GTK_WIDGET (user_data);

  /* Make sure the preference has a string */
  if (gconf_entry_get_value (entry) != NULL && 
      gconf_entry_get_value (entry)->type == GCONF_VALUE_STRING)
    {
      /* Get the new value */
      const gchar* new_setting =
        gconf_value_get_string (gconf_entry_get_value (entry));

      /* Check if it seems valid, give a warning if it doesn't */
      if (strcmp(new_setting, "always")     != 0 &&
          strcmp(new_setting, "local_only") != 0 &&
          strcmp(new_setting, "never")      != 0)
        {
          g_warning("Unrecognized value specified by external program...\n");
        }

      /* Use the new value if it's different than the old */
      if (strcmp(new_setting,old_show_thumbnails_setting) != 0)
        {
          strcpy(old_show_thumbnails_setting, new_setting);
          gtk_entry_set_text (GTK_ENTRY (show_entry), new_setting);
        }
    }
}

void
show_thumbnails_changed_callback (GtkWidget* show_entry, gpointer user_data)
{
  GConfClient* client = GCONF_CLIENT (user_data);

  /* Get the current value */
  const gchar* cur_value =
    gtk_entry_get_text (GTK_ENTRY (show_entry));
 
  if (strcmp(cur_value, "always")     == 0 ||
      strcmp(cur_value, "local_only") == 0 ||
      strcmp(cur_value, "never")      == 0)
    {
      if (strcmp(cur_value, old_show_thumbnails_setting) != 0)
        {
          strcpy(old_show_thumbnails_setting, cur_value);
          gconf_client_set_string (client,
                                   "/apps/nautilus/preferences/show_image_thumbnails",
                                   cur_value,
                                   NULL);
        }
    }
  else
    {
      g_warning("This program needs an error window to warn you that you typed an invalid value.\n");
      gtk_entry_set_text (GTK_ENTRY (show_entry), old_show_thumbnails_setting);
    }
}

/*********** callbacks for thumbnail_limit **********/
void
gconf_thumbnail_limit_callback (GConfClient* client,
                                guint cnxn_id,
                                GConfEntry* entry,
                                gpointer user_data)
{
  GtkWidget* limit_entry;
  limit_entry = GTK_WIDGET (user_data);

  /* Make sure the preference has a string */
  if (gconf_entry_get_value (entry) != NULL && 
      gconf_entry_get_value (entry)->type == GCONF_VALUE_INT)
    {
      /* Get the new value */
      gint new_value =
        gconf_value_get_int (gconf_entry_get_value (entry));

      /* Warn if the value seems invalid */
      if (new_value < 0)
        {
          g_warning("Bad value seems to have been set by external program.\n");
        }

      if (new_value != old_thumbnail_limit)
        {
          old_thumbnail_limit = new_value;
          gchar temp_string[20];
          sprintf(temp_string, "%d", old_thumbnail_limit);
          gtk_entry_set_text (GTK_ENTRY (limit_entry), temp_string);
        }
    }
}

void
thumbnail_limit_changed_callback (GtkWidget* limit_entry, gpointer user_data)
{
  GConfClient* client = GCONF_CLIENT (user_data);

  /* Get the current value */
  const gchar* cur_value =
    gtk_entry_get_text (GTK_ENTRY (limit_entry));

  gboolean is_numeric = TRUE;
  const gchar* temp_copy = cur_value;
  while (g_ascii_isdigit (*temp_copy++))
    ;
  temp_copy--;
  if (*temp_copy)
    is_numeric = FALSE;

  gint new_value = 0;
  if (is_numeric)
    new_value = atoi(cur_value);
 
  if (is_numeric && new_value >= 0)
    {
      if (new_value != old_thumbnail_limit)
        {
          old_thumbnail_limit = new_value;
          gconf_client_set_int (client,
                                "/apps/nautilus/preferences/thumbnail_limit",
                                new_value,
                                NULL);
        }
    }
  else
    {
      g_warning("This program needs an error window to warn you that you typed an invalid value.\n");
      gchar temp_string[20];
      sprintf(temp_string, "%d", old_thumbnail_limit);
      gtk_entry_set_text (GTK_ENTRY (limit_entry), temp_string);
    }
}


void
hook_up_callbacks_and_set_defaults (GladeXML * the_widgets)
{
  GtkWidget *widget;

  /* Get the GConfClient, tell it we want to monitor /apps/nautilus/preferences*/
  GConfClient* client = gconf_client_get_default();
  gconf_client_add_dir(client,
                       "/apps/nautilus/preferences",
                       GCONF_CLIENT_PRELOAD_NONE,
                       NULL);


  /* First, setup the checkbutton for the always_use_browser key */

  /* Get the check_button */
  widget = glade_xml_get_widget (the_widgets, "BrowserMode");

  /* Connect the check_button to a callback that can toggle it when the option
   * is changed by some outside program.
   */
  gconf_client_notify_add(client,
                          "/apps/nautilus/preferences/always_use_browser",
                          gconf_browser_key_callback,
                          widget,
                          NULL,
                          NULL);

  /* Connect the check_button's clicked callback up so that it can change the
   * gconf setting.
   */
  g_signal_connect(G_OBJECT (widget), "clicked",
                   G_CALLBACK (browser_key_toggled_callback), client);

  /* Determine whether button should start activated or not */
  old_browser_setting =
    gconf_client_get_bool (client,
                           "/apps/nautilus/preferences/always_use_browser",
                           NULL);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), old_browser_setting);


  /* Second, setup the text entry for the show_image_thumbnails key */

  /* Get the Entry */
  widget = glade_xml_get_widget (the_widgets, "ShowThumbnailsEntry");

  /* Connect the show thumbnail entry to a callback that can toggle it
   * when the option is changed by some outside program.
   */
  gconf_client_notify_add(client,
                          "/apps/nautilus/preferences/show_image_thumbnails",
                          gconf_show_thumbnails_callback,
                          widget,
                          NULL,
                          NULL);

  /* Connect the show thumbnail entry's activated callback up so that
   * it can change the gconf setting.
   */
  g_signal_connect(G_OBJECT (widget), "activate",
                   G_CALLBACK (show_thumbnails_changed_callback), client);

  /* Make space for storing the old value of the old show_thumbnails setting */
  old_show_thumbnails_setting = (gchar*)malloc(sizeof(gchar[20]));
  /* FIXME: Not necessary, but might consider freeing this later... */

  /* Determine the starting value of this key */
  const gchar* old_value =
    gconf_client_get_string (client,
                             "/apps/nautilus/preferences/show_image_thumbnails",
                             NULL);
  strcpy(old_show_thumbnails_setting, old_value);
  gtk_entry_set_text (GTK_ENTRY (widget), old_show_thumbnails_setting);


  /* Third, setup the text entry for the thumbnail_limit key */

  /* Get the Entry */
  widget = glade_xml_get_widget (the_widgets, "ThumbnailLimitEntry");

  /* Connect the thumbnail limit entry to a callback that can toggle
   * it when the option is changed by some outside program.
   */
  gconf_client_notify_add(client,
                          "/apps/nautilus/preferences/thumbnail_limit",
                          gconf_thumbnail_limit_callback,
                          widget,
                          NULL,
                          NULL);

  /* Connect the thumbnail limit entry's activated callback up so that
   * it can change the gconf setting.
   */
  g_signal_connect(G_OBJECT (widget), "activate",
                   G_CALLBACK (thumbnail_limit_changed_callback), client);

  /* Determine the starting value of this key */
  old_thumbnail_limit =
    gconf_client_get_int (client,
                          "/apps/nautilus/preferences/thumbnail_limit",
                          NULL);
  gchar temp_string[20];
  sprintf(temp_string, "%d", old_thumbnail_limit);
  gtk_entry_set_text (GTK_ENTRY (widget), temp_string);


  /* Get the main_window and connect the close button to gtk_main_quit */
  widget = glade_xml_get_widget (the_widgets, "MainWindow");
  g_signal_connect (G_OBJECT (widget), "delete_event",
                    G_CALLBACK (gtk_main_quit), NULL);

  /* Get the quit button and it to gtk_main_quit */
  widget = glade_xml_get_widget (the_widgets, "CloseButton");
  g_signal_connect (G_OBJECT (widget), "clicked",
                    G_CALLBACK (gtk_main_quit), NULL);
}

int
main (int argc, char **argv)
{
  GladeXML *all_da_widgets;

  gtk_init (&argc, &argv);
  gconf_init(argc, argv, NULL);

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

  /* Connect all the signals to the appropriate callbacks */
  hook_up_callbacks_and_set_defaults (all_da_widgets);

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

  return 0;
}

GTKMM

The files using the C++ language bindings to GTK to make this interface layout into a functioning program are below. First, the ExampleWindow.h header file:

#ifndef EXAMPLE_WINDOW_H
#define EXAMPLE_WINDOW_H

#include <libglademm.h>
#include <gtkmm.h>
#include <gconfmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow(BaseObjectType* cobject,
                const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml);
  virtual ~ExampleWindow();

protected:
  void browser_key_changed(guint cnxn_id, Gnome::Conf::Entry entry);
  void browser_key_toggled();
  void show_thumbnails_key_changed(guint cnxn_id, Gnome::Conf::Entry entry);
  void show_thumbnails_modified();
  void thumbnail_limit_key_changed(guint cnxn_id, Gnome::Conf::Entry entry);
  void thumbnail_limit_modified();

  Glib::RefPtr<Gnome::Conf::Client> d_conf_client;
  Gtk::CheckButton*                 d_browser_checkbutton;
  bool                              d_old_browser_setting;
  Gtk::Entry*                       d_show_thumbnail_entry;
  Glib::ustring                     d_old_show_thumbnails_setting;
  Gtk::Entry*                       d_thumbnail_limit_entry;
  gint                              d_old_thumbnail_limit;
};

#endif // EXAMPLE_WINDOW_H

Next is the ExampleWindow.cc file:

#include "ExampleWindow.h"
#include <sstream>

ExampleWindow::ExampleWindow(
  BaseObjectType* base_object,
  const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml)
  : Gtk::Window(base_object)
{
  // Get the client and tell it we want to monitor /apps/nautilus/preferences
  d_conf_client = Gnome::Conf::Client::get_default_client();
  d_conf_client->add_dir("/apps/nautilus/preferences");


  /* First, setup the checkbutton for the always_use_browser key */

  // Get the check_button
  glade_xml->get_widget("BrowserMode", d_browser_checkbutton);

  // Connect the check_button to a callback that can toggle it when the option
  // is changed by some outside program.
  d_conf_client->notify_add(
    "/apps/nautilus/preferences/always_use_browser",
    sigc::mem_fun(*this, &ExampleWindow::browser_key_changed)
    );

  // Connect the check_button's clicked callback up so that it can change the
  // gconf setting.
  d_browser_checkbutton->signal_clicked().connect(
    sigc::mem_fun(*this, &ExampleWindow::browser_key_toggled) );

  // Determine whether button should start activated or not
  d_old_browser_setting = 
    d_conf_client->get_bool("/apps/nautilus/preferences/always_use_browser");
  d_browser_checkbutton->set_active(d_old_browser_setting);


  /* Second, setup the text entry for the show_image_thumbnails key */

  // Get the Entry
  glade_xml->get_widget("ShowThumbnailsEntry", d_show_thumbnail_entry);

  // Connect the show thumbnail entry to a callback that can toggle it
  // when the option is changed by some outside program.
  d_conf_client->notify_add(
    "/apps/nautilus/preferences/show_image_thumbnails",
    sigc::mem_fun(*this, &ExampleWindow::show_thumbnails_key_changed)
    );

  // Connect the show thumbnail entry's activated callback up so that
  // it can change the gconf setting.
  d_show_thumbnail_entry->signal_activate().connect(
    sigc::mem_fun(*this, &ExampleWindow::show_thumbnails_modified) );

  // Determine the starting value of this key
  d_old_show_thumbnails_setting =
    d_conf_client->get_string(
      "/apps/nautilus/preferences/show_image_thumbnails");
  d_show_thumbnail_entry->set_text(d_old_show_thumbnails_setting);


  /* Third, setup the text entry for the thumbnail_limit key */

  // Get the Entry
  glade_xml->get_widget("ThumbnailLimitEntry", d_thumbnail_limit_entry);

  // Connect the thumbnail limit entry to a callback that can toggle
  // it when the option is changed by some outside program.
  d_conf_client->notify_add(
    "/apps/nautilus/preferences/thumbnail_limit",
    sigc::mem_fun(*this, &ExampleWindow::thumbnail_limit_key_changed)
    );

  // Connect the thumbnail limit entry's activated callback up so that
  // it can change the gconf setting.
  d_thumbnail_limit_entry->signal_activate().connect(
    sigc::mem_fun(*this, &ExampleWindow::thumbnail_limit_modified) );

  // Determine the starting value of this key
  d_old_thumbnail_limit =
    d_conf_client->get_int("/apps/nautilus/preferences/thumbnail_limit");
  gchar temp_string[20];
  sprintf(temp_string, "%d", d_old_thumbnail_limit);
  d_thumbnail_limit_entry->set_text(temp_string);



  // Get the close button and connect it to hide
  Gtk::Button* close_button;
  glade_xml->get_widget("CloseButton", close_button);
  close_button->signal_clicked().connect(
    sigc::mem_fun(*this, &Gtk::Widget::hide));
}

ExampleWindow::~ExampleWindow()
{
}

void
ExampleWindow::browser_key_changed(guint cnxn_id, Gnome::Conf::Entry entry)
{
  // Make sure the preference has a valid value
  if (entry.get_value().get_type() == Gnome::Conf::VALUE_BOOL) {
    // Get the new value
    bool new_browser_setting = entry.get_value().get_bool();

    // Try to handle asynchronous-ness of GConf and prevent calling
    // checkbutton_toggled again if this function was called as a
    // result of the d_conf_client->set() function call.
    if (new_browser_setting != d_old_browser_setting) {
      d_old_browser_setting = new_browser_setting;
      d_browser_checkbutton->set_active(new_browser_setting);
    }
  }
}

void
ExampleWindow::browser_key_toggled()
{
  // Determine whether the checkbutton is already set or not
  bool is_set = d_browser_checkbutton->get_active();
 
  // Try to handle asynchronous-ness of GConf and prevent calling
  // key_changed again if this function was called as a result of the
  // d_checkbutton->set_active() function call.
  if (is_set != d_old_browser_setting) {
    d_old_browser_setting = is_set;
    d_conf_client->set("/apps/nautilus/preferences/always_use_browser", is_set);
  }
}

void
ExampleWindow::show_thumbnails_key_changed(
  guint cnxn_id, 
  Gnome::Conf::Entry entry)
{
  // Make sure the preference has a valid value
  if (entry.get_value().get_type() == Gnome::Conf::VALUE_STRING) {
    // Get the new value
    Glib::ustring new_setting = entry.get_value().get_string();

    // Check if it seems valid, give a warning if it doesn't
    if ((new_setting != "always") &&
        (new_setting != "local_only") &&
        (new_setting != "never"))
    {
      g_warning("Unrecognized value specified by external program...\n");
    }

    // Use the new value if it's different than the old
    if (new_setting != d_old_show_thumbnails_setting) {
      d_old_show_thumbnails_setting = new_setting;
      d_show_thumbnail_entry->set_text(new_setting);
    }
  }
}

void
ExampleWindow::show_thumbnails_modified()
{
  // Get the current value
  Glib::ustring cur_value = d_show_thumbnail_entry->get_text();
 
  if ((cur_value == "always")     ||
      (cur_value == "local_only") ||
      (cur_value == "never")) {
    if (cur_value != d_old_show_thumbnails_setting) {
      d_old_show_thumbnails_setting = cur_value;
      d_conf_client->set("/apps/nautilus/preferences/show_image_thumbnails",
                         cur_value);
    }
  } else {
    g_warning("This program needs an error window to warn you that you typed an invalid value.\n");
    d_show_thumbnail_entry->set_text(d_old_show_thumbnails_setting);
  }
}

void
ExampleWindow::thumbnail_limit_key_changed(
  guint cnxn_id, 
  Gnome::Conf::Entry entry)
{
  // Make sure the preference has a valid value
  if (entry.get_value().get_type() == Gnome::Conf::VALUE_INT) {
    // Get the new value
    gint new_value = entry.get_value().get_int();

    // Check if it seems valid, give a warning if it doesn't
    if (new_value < 0) {
      g_warning("Bad value seems to have been set by external program.\n");
    }

    // Use the new value if it's different than the old
    if (new_value != d_old_thumbnail_limit) {
      d_old_thumbnail_limit = new_value;
      gchar temp_string[20];
      sprintf(temp_string, "%d", d_old_thumbnail_limit);
      d_thumbnail_limit_entry->set_text(temp_string);
    }
  }
}

void
ExampleWindow::thumbnail_limit_modified()
{
  // Get the current value
  Glib::ustring cur_value = d_thumbnail_limit_entry->get_text();
  /*
  size_type bad_char_position = cur_value.find_first_not_of("1234567890");

  gint new_value = 0;
  if (bad_char_position != string::npos)
    new_value = atoi(cur_value->c_str());
  */

  std::istringstream sstr(cur_value);
  gint new_value;
  sstr >> new_value;

  if ( !sstr.fail() && new_value >= 0) {
    if (new_value != d_old_thumbnail_limit) {
      d_old_thumbnail_limit = new_value;
      d_conf_client->set("/apps/nautilus/preferences/thumbnail_limit",
                         new_value);
    }
  } else {
    g_warning("This program needs an error window to warn you that you typed an invalid value.\n");
    gchar temp_string[20];
    sprintf(temp_string, "%d", d_old_thumbnail_limit);
    d_thumbnail_limit_entry->set_text(temp_string);
  }
}

And finally, here is the example-2.cc file which glues everything together:

// This program monitors the
// /apps/nautilus/preferences/always_use_browser,
// /apps/nautilus/preferences/show_image_thumbnails, and
// /apps/nautilus/preferences/thumbnail_limit gconf keys, and allows
// the user to change them as well.

#include "ExampleWindow.h"

using namespace std;

int
main (int argc, char *argv[])
{
  Gnome::Conf::init();
  Gtk::Main kit(argc, argv);

  Glib::RefPtr<Gnome::Glade::Xml> all_da_widgets;

  // load the interface
  all_da_widgets = Gnome::Glade::Xml::create("example-2.glade");

  // Get the main window
  ExampleWindow* window;
  all_da_widgets->get_widget_derived("MainWindow", window);

  // start the event loop
  Gtk::Main::run( *window );

  return 0;
}

GTK2-PERL

The file using the perl language bindings to GTK to make this interface layout into a functioning program is below.

#!/usr/bin/perl -w

# This program monitors the
# /apps/nautilus/preferences/always_use_browser,
# /apps/nautilus/preferences/show_image_thumbnails, and
# /apps/nautilus/preferences/thumbnail_limit gconf keys, and allows
# the user to change them as well.

use Glib qw(TRUE FALSE);
use Gtk2 '-init';
use Gtk2::GladeXML;
use Gnome2::GConf;

# Just to be pedantic...
use strict;
use vars qw($all_da_widgets);

sub gconf_browser_key_callback
{
  my ($check_button, $new_browser_setting, $old_browser_setting) = @_;

  # Try to handle asynchronous-ness of GConf and prevent calling
  # checkbutton_toggled_callback again if this function was called
  # as a result of the $client->set_bool function call.
  if ($new_browser_setting != $$old_browser_setting) {
    $$old_browser_setting = $new_browser_setting;
    $check_button->set_active($new_browser_setting);
  }
}

sub browser_key_toggled_callback
{
  my ($check_button, $client, $old_browser_setting) = @_;

  # Determine whether the checkbutton is already set or not
  my $is_set = $check_button->get_active;
 
  # Try to handle asynchronous-ness of GConf and prevent calling
  # gconf_browser_key_callback again if this function was called as a
  # result of the $check_button->set_active function call.
  if ($is_set != $$old_browser_setting) {
    $$old_browser_setting = $is_set;
    $client->set("/apps/nautilus/preferences/always_use_browser",
                 { type => 'bool', value => $is_set }
                );
  }
}

sub gconf_show_thumbnails_callback
{
  my ($show_entry, $new_setting, $old_show_thumbnails_setting) = @_;

  # Check if the new_setting seems valid, give a warning if it doesn't
  if (($new_setting ne "always") &&
      ($new_setting ne "local_only") &&
      ($new_setting ne "never"))
  {
    warn "Unrecognized value specified by external program...\n";
  }

  # Use the new value if it's different than the old 
  if ($new_setting ne $$old_show_thumbnails_setting) {
    $$old_show_thumbnails_setting = $new_setting;
    $show_entry->set_text($new_setting);
  }
}

sub show_thumbnails_changed_callback
{
  my ($show_entry, $client, $old_show_thumbnails_setting) = @_;

  # Get the current value
  my $cur_value = $show_entry->get_text;

  if (($cur_value eq "always")     ||
      ($cur_value eq "local_only") ||
      ($cur_value eq "never"))
  {
    if ($cur_value ne $$old_show_thumbnails_setting) {
      $$old_show_thumbnails_setting = $cur_value;
      $client->set("/apps/nautilus/preferences/show_image_thumbnails",
                   {type => 'string', value => $cur_value }
                  );
    }
  } else {
    warn "This program needs an error window to warn you" .
         " that you typed an invalid value.\n";
    $show_entry->set_text($$old_show_thumbnails_setting);
  }
}

sub gconf_thumbnail_limit_callback
{
  my ($limit_entry, $new_value, $old_thumbnail_limit) = @_;

  # Warn if the value seems invalid 
  if ($new_value < 0) {
    warn "Bad value seems to have been set by external program.\n";
  }

  if ($new_value != $$old_thumbnail_limit) {
    $$old_thumbnail_limit = $new_value;
    $limit_entry->set_text($new_value);
  }
}

sub thumbnail_limit_changed_callback
{
  my ($limit_entry, $client, $old_thumbnail_limit) = @_;

  # Get the current value
  my $new_value = $limit_entry->get_text;

  if ( $new_value =~ /^\d+$/ ) {
    if ($new_value != $$old_thumbnail_limit) {
      $$old_thumbnail_limit = $new_value;
      $client->set("/apps/nautilus/preferences/thumbnail_limit",
                   {type => 'int', value => $new_value }
                  );
    }
  } else {
    warn "This program needs an error window to warn you" .
         " that you typed an invalid value.\n";
    $limit_entry->set_text($$old_thumbnail_limit);
  }
}

sub hook_up_callbacks_and_set_defaults
{
  my ($the_widgets) = @_;

  my ($old_browser_setting, $old_show_thumbnails_setting, $old_thumbnail_limit);

  # Get the GconfClient, tell it we want to monitor /apps/nautilus/preferences
  my $client = Gnome2::GConf::Client->get_default;
  $client->add_dir("/apps/nautilus/preferences", 'preload-none');

  # FIRST, setup the checkbutton for the always_use_browser key

  # Get the check_button
  my $check_button = $the_widgets->get_widget('BrowserMode');

  # Determine whether button should start activated or not
  $old_browser_setting = 
    $client->get_bool("/apps/nautilus/preferences/always_use_browser");
  $check_button->set_active($old_browser_setting);

  # Connect the check_button to a callback that can toggle it when the option
  # is changed by some outside program.
  $client->notify_add("/apps/nautilus/preferences/always_use_browser",
                      sub {
                        my ($client, $cnxn_id, $entry) = @_;

                        # Make sure the preference has a valid value
                        return unless $entry->{value} &&
                                      $entry->{value}->{type} eq 'bool';

                        &gconf_browser_key_callback($check_button, 
                                                    $entry->{value}->{value},
                                                    \$old_browser_setting);
                      }
                     );

  # Connect the check_button's clicked callback up so that it can
  # change the gconf setting.
  $check_button->signal_connect( clicked => 
                                 sub { 
                                   &browser_key_toggled_callback(
                                     $check_button,
                                     $client,
                                     \$old_browser_setting);
                                 }
                               );

  # SECOND, setup the text entry for the show_image_thumbnails key

  # Get the Entry
  my $show_entry = $the_widgets->get_widget('ShowThumbnailsEntry');

  # Determine the intial string for the show thumbnail entry
  $old_show_thumbnails_setting =
    $client->get_string("/apps/nautilus/preferences/show_image_thumbnails");
  $show_entry->set_text($old_show_thumbnails_setting);

  # Connect the show thumbnail entry to a callback that can toggle it
  # when the option is changed by some outside program.
  $client->notify_add("/apps/nautilus/preferences/show_image_thumbnails",
                      sub {
                        my ($client, $cnxn_id, $entry) = @_;

                        # Make sure the preference has a valid value
                        return unless $entry->{value} &&
                                      $entry->{value}->{type} eq 'string';

                        &gconf_show_thumbnails_callback(
                          $show_entry, 
                          $entry->{value}->{value},
                          \$old_show_thumbnails_setting);
                      }
                     );

  # Connect the show thumbnail entry's activated callback up so that
  # it can change the gconf setting.
  $show_entry->signal_connect( activate => 
                               sub { 
                                 &show_thumbnails_changed_callback(
                                   $show_entry,
                                   $client,
                                   \$old_show_thumbnails_setting);
                                 }
                               );

  # THIRD, setup the text entry for the thumbnail_limit key

  # Get the Entry
  my $limit_entry = $the_widgets->get_widget('ThumbnailLimitEntry');

  # Determine the starting value of the limit
  $old_thumbnail_limit =
    $client->get_int ("/apps/nautilus/preferences/thumbnail_limit");
  $limit_entry->set_text($old_thumbnail_limit);

  # Connect the thumbnail limit entry to a callback that can toggle it
  # when the option is changed by some outside program.
  $client->notify_add("/apps/nautilus/preferences/thumbnail_limit",
                      sub {
                        my ($client, $cnxn_id, $entry) = @_;

                        # Make sure the preference has a valid value
                        return unless $entry->{value} &&
                                      $entry->{value}->{type} eq 'int';

                        &gconf_thumbnail_limit_callback(
                          $limit_entry, 
                          $entry->{value}->{value},
                          \$old_thumbnail_limit);
                      }
                     );

  # Connect the thumbnail limit entry's activated callback up so that
  # it can change the gconf setting.
  $limit_entry->signal_connect( activate => 
                                sub { 
                                  &thumbnail_limit_changed_callback(
                                    $limit_entry,
                                    $client,
                                    \$old_thumbnail_limit);
                                  }
                                );

  # Get the main_window and make the close button quit
  my $main_window = $the_widgets->get_widget('MainWindow');
  $main_window->signal_connect( delete_event => 
                                sub { Gtk2->main_quit; return TRUE; } 
                              );

  # Get the quit button and it to gtk_main_quit
  my $close_button = $the_widgets->get_widget('CloseButton');
  $close_button->signal_connect( clicked => sub { Gtk2->main_quit; } );
}

  # load the interface
  $all_da_widgets = Gtk2::GladeXML->new('example-2.glade');

  # Connect all the signals to the appropriate callbacks
  &hook_up_callbacks_and_set_defaults($all_da_widgets);

  # start the event loop
  Gtk2->main;

  # Return 0, meaning no errors
  0;

PYGTK

The file using the python language bindings to GTK to make this interface layout into a functioning program is below.

#!/usr/bin/env python

# This program monitors the
# /apps/nautilus/preferences/always_use_browser,
# /apps/nautilus/preferences/show_image_thumbnails, and
# /apps/nautilus/preferences/thumbnail_limit gconf keys, and allows
# the user to change them as well.

import gtk
import gtk.glade
import gconf
import re

class ExampleWindow:
  def __init__(self, glade_file):
    # Parse the glade file
    self.all_da_widgets = gtk.glade.XML(glade_file)

    # Get the client and tell it we want to monitor /apps/nautilus/preferences
    self.conf_client = gconf.client_get_default()
    self.conf_client.add_dir("/apps/nautilus/preferences", \
                             gconf.CLIENT_PRELOAD_NONE);


    # First, setup the checkbutton for the always_use_browser key 

    # Get the check_button
    self.browser_checkbutton = self.all_da_widgets.get_widget("BrowserMode")

    # Connect the check_button to a callback that can toggle it when the option
    # is changed by some outside program.
    self.conf_client.notify_add(                       \
      "/apps/nautilus/preferences/always_use_browser", \
      self.browser_key_changed                         \
      )

    # Connect the check_button's clicked callback up so that it can change the
    # gconf setting.
    self.browser_checkbutton.connect("clicked", self.browser_key_toggled)

    # Determine whether button should start activated or not
    self.old_browser_setting = \
      self.conf_client.get_bool("/apps/nautilus/preferences/always_use_browser")
    self.browser_checkbutton.set_active(self.old_browser_setting)


    # Second, setup the text entry for the show_image_thumbnails key 

    # Get the Entry
    self.show_thumbnail_entry = \
      self.all_da_widgets.get_widget("ShowThumbnailsEntry")

    # Connect the show thumbnail entry to a callback that can toggle it
    # when the option is changed by some outside program.
    self.conf_client.notify_add(                          \
      "/apps/nautilus/preferences/show_image_thumbnails", \
      self.show_thumbnails_key_changed                    \
      )

    # Connect the show thumbnail entry's activated callback up so that
    # it can change the gconf setting.
    self.show_thumbnail_entry.connect("activate", self.show_thumbnails_modified)

    # Determine the starting value of this key
    self.old_show_thumbnails_setting = \
      self.conf_client.get_string(     \
        "/apps/nautilus/preferences/show_image_thumbnails")
    self.show_thumbnail_entry.set_text(self.old_show_thumbnails_setting)


    # Third, setup the text entry for the thumbnail_limit key

    # Get the Entry
    self.thumbnail_limit_entry = \
      self.all_da_widgets.get_widget("ThumbnailLimitEntry")

    # Connect the thumbnail limit entry to a callback that can toggle
    # it when the option is changed by some outside program.
    self.conf_client.notify_add(
      "/apps/nautilus/preferences/thumbnail_limit",
      self.thumbnail_limit_key_changed
      )

    # Connect the thumbnail limit entry's activated callback up so that
    # it can change the gconf setting.
    self.thumbnail_limit_entry.connect("activate", self.thumbnail_limit_modified)

    # Determine the starting value of this key
    self.old_thumbnail_limit = \
      self.conf_client.get_int("/apps/nautilus/preferences/thumbnail_limit");
    self.thumbnail_limit_entry.set_text(str(self.old_thumbnail_limit));


    # Get the close button and connect it to hide
    close_button = self.all_da_widgets.get_widget("CloseButton")
    close_button.connect("clicked", gtk.mainquit)

    # Get the close button and connect it to hide
    main_window = self.all_da_widgets.get_widget("MainWindow")
    main_window.connect("delete_event", gtk.mainquit)

  def browser_key_changed(self, client, connection_id, entry, args):

    # Make sure the preference has a valid value
    if (entry.get_value().type == gconf.VALUE_BOOL):
      # Get the new value
      new_browser_setting = entry.get_value().get_bool()

      # Try to handle asynchronous-ness of GConf and prevent calling
      # checkbutton_toggled again if this function was called as a
      # result of the self.conf_client.set() function call.
      if (new_browser_setting != self.old_browser_setting):
        self.old_browser_setting = new_browser_setting
        self.browser_checkbutton.set_active(new_browser_setting)

  def browser_key_toggled(self, checkbutton_widget):

    # Determine whether the checkbutton is already set or not
    is_set = self.browser_checkbutton.get_active()
 
    # Try to handle asynchronous-ness of GConf and prevent calling
    # key_changed again if this function was called as a result of the
    # self.checkbutton.set_active() function call.
    if (is_set != self.old_browser_setting):
      self.old_browser_setting = is_set;
      self.conf_client.set_bool("/apps/nautilus/preferences/always_use_browser",\
                                is_set)

  def show_thumbnails_key_changed(self, client, connection_id, entry, args):

    # Make sure the preference has a valid value
    if (entry.get_value().type == gconf.VALUE_STRING):
      # Get the new value
      new_setting = entry.get_value().get_string()

      # Check if it seems valid, give a warning if it doesn't
      if ((new_setting != "always")     and \
          (new_setting != "local_only") and \
          (new_setting != "never")):
        # I couldn't find an equivalent for g_warning
        print "Unrecognized value specified by external program...\n"

      # Use the new value if it's different than the old
      if (new_setting != self.old_show_thumbnails_setting):
        self.old_show_thumbnails_setting = new_setting
        self.show_thumbnail_entry.set_text(new_setting)

  def show_thumbnails_modified(self, show_thumbnail_entry):

    # Get the current value
    cur_value = self.show_thumbnail_entry.get_text()
 
    if ((cur_value == "always")     or
        (cur_value == "local_only") or
        (cur_value == "never")):
      if (cur_value != self.old_show_thumbnails_setting):
        self.old_show_thumbnails_setting = cur_value
        self.conf_client.set_string(
          "/apps/nautilus/preferences/show_image_thumbnails",
          cur_value);
    else:
      # I couldn't find an equivalent for g_warning
      print "This program needs an error window to warn you" + \
            " that you typed an invalid value."
      self.show_thumbnail_entry.set_text(self.old_show_thumbnails_setting)

  def thumbnail_limit_key_changed(self, client, connection_id, entry, args):

    # Make sure the preference has a valid value
    if (entry.get_value().type == gconf.VALUE_INT):
      # Get the new value
      new_value = entry.get_value().get_int()

      # Check if it seems valid, give a warning if it doesn't
      if (new_value < 0):
        # I couldn't find an equivalent for g_warning
        print "Bad value seems to have been set by external program."

      # Use the new value if it's different than the old
      if (new_value != self.old_thumbnail_limit):
        self.old_thumbnail_limit = new_value
        self.thumbnail_limit_entry.set_text(str(new_value))

  def thumbnail_limit_modified(self, thumbnail_limit_entry):

    # Get the current value
    new_value = self.thumbnail_limit_entry.get_text()

    nonnegative_number_regex = re.compile(r'^\d+$')
    if nonnegative_number_regex.match(new_value):
      if (new_value != self.old_thumbnail_limit):
        self.old_thumbnail_limit = new_value
        self.conf_client.set_int("/apps/nautilus/preferences/thumbnail_limit",\
                                 int(new_value))
      
    else:
      # I couldn't find an equivalent for g_warning
      print "This program needs an error window to warn you" + \
            " that you typed an invalid value."
      self.thumbnail_limit_entry.set_text(str(self.old_thumbnail_limit))

# Create the ExampleWindow
window = ExampleWindow("example-2.glade")

# start the event loop
gtk.main()