commit ba2a0208c154d9af79048de1f435419483e7532c
Author: Thorsten Otto <thotto@users.sourceforge.net>
Date:   Tue Mar 24 18:10:23 2015 +0100

    Add Gtk2::Assistant to gtk-demo

diff --git a/gtk-demo/assistant.pl b/gtk-demo/assistant.pl
new file mode 100644
index 0000000..917153a
--- /dev/null
+++ b/gtk-demo/assistant.pl
@@ -0,0 +1,242 @@
+#!/usr/bin/perl -w
+#
+# Assistant
+#
+# Demonstrates a sample multistep assistant. Assistants are used to divide
+# an operation into several simpler sequential steps, and to guide the user
+# through these steps.
+#
+
+package assistant;
+
+use strict;
+use warnings;
+use Glib ':constants';
+use Gtk2;
+#include "demo-common.h"
+
+my $assistant = undef;
+my $progress_bar = undef;
+
+
+sub apply_changes_gradually($) {
+  my $fraction;
+  
+  # Work, work, work...
+  Gtk2::Gdk::Threads->leave();
+  $fraction = $progress_bar->get_fraction();
+  $fraction += 0.05;
+  
+  my $cont = TRUE;
+  if ($fraction < 1.0) {
+  	$progress_bar->set_fraction($fraction);
+  } else {
+    # Close automatically once changes are fully applied.
+  	$assistant->destroy();
+  	undef $assistant;
+  	$cont = FALSE;
+  }
+  Gtk2::Gdk::Threads->enter();
+  return $cont;
+}
+
+
+sub on_assistant_apply($$)
+{
+  my ($widget, $data) = @_;
+  # Start a timer to simulate changes taking a few seconds to apply.
+  Glib::Timeout->add(100, \&apply_changes_gradually, undef);
+}
+
+
+sub on_assistant_close_cancel($$)
+{
+  my ($widget, $assistant) = @_;
+  $$assistant->destroy();
+  undef $$assistant;
+}
+
+
+sub on_assistant_prepare($$$)
+{
+  my ($widget, $page, $data) = @_;
+  my ($current_page, $n_pages, $title);
+  
+  $current_page = $widget->get_current_page();
+  $n_pages = $widget->get_n_pages();
+  
+  $title = sprintf("Sample assistant (%d of %d)", $current_page + 1, $n_pages);
+  $widget->window()->set_title($title);
+
+  # The fourth page (counting from zero) is the progress page.  The
+  # user clicked Apply to get here so we tell the assistant to commit,
+  # which means the changes up to this point are permanent and cannot
+  # be cancelled or revisited.
+  if ($current_page == 3) {
+      $widget->commit();
+  }
+}
+
+
+sub on_entry_changed($$)
+{
+  my ($widget, $data) = @_;
+  my $assistant = $data;
+  my ($current_page, $page_number, $text);
+  
+  $page_number = $assistant->get_current_page();
+  $current_page = $assistant->get_nth_page($page_number);
+  $text = $widget->get_text();
+
+  if ($text && $text ne '') {
+    $assistant->set_page_complete($current_page, TRUE);
+  } else {
+    $assistant->set_page_complete($current_page, FALSE);
+  }
+}
+
+
+sub create_page1($)
+{
+  my $assistant = shift;
+  my ($box, $label, $entry, $pixbuf);
+
+  $box = Gtk2::HBox->new(FALSE, 12);
+  $box->set_border_width(12);
+
+  $label = Gtk2::Label->new("You must fill out this entry to continue:");
+  $box->pack_start($label, FALSE, FALSE, 0);
+
+  $entry = Gtk2::Entry->new();
+  $box->pack_start($entry, TRUE, TRUE, 0);
+  $entry->signal_connect("changed",
+		    \&on_entry_changed, $assistant);
+
+  $box->show_all();
+  $assistant->append_page($box);
+  $assistant->set_page_title($box, "Page 1");
+  $assistant->set_page_type($box, 'GTK_ASSISTANT_PAGE_INTRO');
+
+  $pixbuf = $assistant->render_icon('gtk-dialog-info', 'GTK_ICON_SIZE_DIALOG');
+  $assistant->set_page_header_image($box, $pixbuf);
+  undef $pixbuf;
+}
+
+
+sub create_page2($)
+{
+  my $assistant = shift;
+  my ($box, $checkbutton, $pixbuf);
+  
+  $box = Gtk2::VBox->new(12, FALSE);
+  $box->set_border_width(12);
+
+  $checkbutton = Gtk2::CheckButton->new_with_label("This is optional data, you may continue " .
+						 "even if you do not check this");
+  $box->pack_start($checkbutton, FALSE, FALSE, 0);
+
+  $box->show_all();
+  $assistant->append_page($box);
+  $assistant->set_page_complete($box, TRUE);
+  $assistant->set_page_title($box, "Page 2");
+
+  $pixbuf = $assistant->render_icon('gtk-dialog-info', 'GTK_ICON_SIZE_DIALOG');
+  $assistant->set_page_header_image($box, $pixbuf);
+  undef $pixbuf;
+}
+
+
+sub create_page3($)
+{
+  my $assistant = shift;
+  my ($label, $pixbuf);
+
+  $label = Gtk2::Label->new ("This is a confirmation page, press 'Apply' to apply changes");
+
+  $label->show();
+  $assistant->append_page($label);
+  $assistant->set_page_type($label, 'GTK_ASSISTANT_PAGE_CONFIRM');
+  $assistant->set_page_complete($label, TRUE);
+  $assistant->set_page_title($label, "Confirmation");
+
+  $pixbuf = $assistant->render_icon('gtk-dialog-info', 'GTK_ICON_SIZE_DIALOG');
+  $assistant->set_page_header_image($label, $pixbuf);
+  undef $pixbuf;
+}
+
+
+sub create_page4($)
+{
+  my $assistant = shift;
+  my ($page);
+
+  $page = Gtk2::Alignment->new (0.5, 0.5, 0.5, 0.0);
+
+  $progress_bar = Gtk2::ProgressBar->new();
+  $page->add($progress_bar);
+
+  $page->show_all();
+  $assistant->append_page($page);
+  $assistant->set_page_type($page, 'GTK_ASSISTANT_PAGE_PROGRESS');
+  $assistant->set_page_title($page, "Applying changes");
+
+  # This prevents the assistant window from being
+  # closed while we're "busy" applying changes.
+  $assistant->set_page_complete($page, FALSE);
+}
+
+sub do {  
+  my $do_widget = shift;
+
+  if (!$assistant) {
+      $assistant = Gtk2::Assistant->new ();
+
+	  $assistant->set_default_size(-1, 300);
+
+      $assistant->set_screen ($do_widget->get_screen)
+        if Gtk2->CHECK_VERSION (2, 2, 0);
+
+      create_page1 ($assistant);
+      create_page2 ($assistant);
+      create_page3 ($assistant);
+      create_page4 ($assistant);
+
+      $assistant->signal_connect ("cancel",
+			\&on_assistant_close_cancel, \$assistant);
+      $assistant->signal_connect ("close",
+			\&on_assistant_close_cancel, \$assistant);
+      $assistant->signal_connect ("apply",
+			\&on_assistant_apply, undef);
+      $assistant->signal_connect ("prepare",
+			\&on_assistant_prepare, undef);
+    }
+
+  if (!$assistant->visible()) {
+      $assistant->show();
+  } else {
+      $assistant->destroy();
+      $assistant = undef;
+  }
+
+  return $assistant;
+}
+
+
+1;
+__END__
+Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
+full list)
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by the Free
+Software Foundation; either version 2.1 of the License, or (at your option) any
+later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU Library General Public License for more
+details.
+
+You should have received a copy of the GNU Library General Public License along
+with this library; if not, write to the Free Software Foundation, Inc., 59
+Temple Place - Suite 330, Boston, MA  02111-1307  USA.
diff --git a/gtk-demo/main.pl b/gtk-demo/main.pl
index d3949a6..8cc3245 100644
--- a/gtk-demo/main.pl
+++ b/gtk-demo/main.pl
@@ -33,6 +33,7 @@ my @child1 = (
 
 @testgtk_demos = (
   { title => "Application main window",     filename => "appwindow.pl",     func => 'stub', }, 
+  { title => "Assistant",                   filename => "assistant.pl",     func => 'stub', available => sub { Gtk2->CHECK_VERSION (2, 10, 0); } },
   { title => "Button Boxes",                filename => "button_box.pl",    func => 'stub', }, 
   { title => "Change Display",              filename => "changedisplay.pl", func => 'stub', }, 
   { title => "Color Selector",              filename => "colorsel.pl",      func => 'stub', }, 
@@ -558,6 +559,7 @@ sub create_tree {
    # want more we probably have to use a recursing function.
    #
    foreach my $d (@testgtk_demos) {
+      next if ($d->{available} && !$d->{available}->());
       my $iter = $model->append (undef);
 
       $model->set ($iter,
commit 376464716f5c2a3c019ba03358fcd6adb44e4018
Author: Thorsten Otto <thotto@users.sourceforge.net>
Date:   Tue Mar 24 18:12:50 2015 +0100

    Add Gtk2::Builder to gtk-demo

diff --git a/gtk-demo/builder.pl b/gtk-demo/builder.pl
new file mode 100644
index 0000000..0437050
--- /dev/null
+++ b/gtk-demo/builder.pl
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+#
+# Builder
+#
+# Demonstrates an interface loaded from a XML description.
+#
+
+package builder;
+
+use strict;
+use warnings;
+use Glib ':constants';
+use Gtk2;
+#include "demo-common.h"
+
+my $builder = undef;
+my $window = undef;
+
+
+sub quit_activate($) {
+  my $action = shift;
+  my $window;
+
+  $window = $builder->get_object("window1");
+  $window->destroy();
+}
+
+
+sub about_activate($) {
+  my $action = shift;
+  my $about_dlg;
+
+  $about_dlg = $builder->get_object("aboutdialog1");
+  $about_dlg->run();
+  $about_dlg->hide();
+}
+
+
+sub do {  
+  my $do_widget = shift;
+  my $filename;
+  
+  if (!$window) {
+      $builder = Gtk2::Builder->new();
+      eval {
+        $filename = main::demo_find_file ("demo.ui");
+        $builder->add_from_file($filename);
+      };
+      warn "ERROR: $@"
+            if $@;
+      $builder->connect_signals();
+      $window = $builder->get_object("window1");
+      $window->set_screen ($do_widget->get_screen)
+        if Gtk2->CHECK_VERSION (2, 2, 0);
+      $window->signal_connect("destroy", sub { $window = undef; });
+  }
+
+  if (!$window->visible()) {
+      $window->show();
+  } else {
+      $window->destroy();
+  }
+
+  return $window;
+}
+
+
+1;
+__END__
+Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
+full list)
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by the Free
+Software Foundation; either version 2.1 of the License, or (at your option) any
+later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU Library General Public License for more
+details.
+
+You should have received a copy of the GNU Library General Public License along
+with this library; if not, write to the Free Software Foundation, Inc., 59
+Temple Place - Suite 330, Boston, MA  02111-1307  USA.
diff --git a/gtk-demo/demo.ui b/gtk-demo/demo.ui
new file mode 100644
index 0000000..57dd232
--- /dev/null
+++ b/gtk-demo/demo.ui
@@ -0,0 +1,258 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<interface domain="gtk20">
+    <object class="GtkListStore" id="liststore1">
+      <columns>
+        <column type="gchararray"/>
+        <column type="gchararray"/>
+        <column type="gint"/>
+        <column type="gchararray"/>
+      </columns>
+      <data>
+        <row>
+          <col id="0" translatable="yes">John</col>
+          <col id="1" translatable="yes">Doe</col>
+          <col id="2">25</col>
+          <col id="3" translatable="yes">This is the John Doe row</col>
+        </row>
+        <row>
+          <col id="0" translatable="yes">Mary</col>
+          <col id="1" translatable="yes">Unknown</col>
+          <col id="2">50</col>
+          <col id="3" translatable="yes">This is the Mary Unknown row</col>
+        </row>
+      </data>
+    </object>
+    <object class="GtkUIManager" id="uimanager">
+        <child>
+            <object class="GtkActionGroup" id="DefaultActions">
+                <child>
+                    <object class="GtkAction" id="Copy">
+                        <property name="name">Copy</property>
+                        <property name="tooltip" translatable="yes">Copy selected object into the clipboard</property>
+                        <property name="stock_id">gtk-copy</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="Cut">
+                        <property name="name">Cut</property>
+                        <property name="tooltip" translatable="yes">Cut selected object into the clipboard</property>
+                        <property name="stock_id">gtk-cut</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="EditMenu">
+                        <property name="name">EditMenu</property>
+                        <property name="label" translatable="yes">_Edit</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="FileMenu">
+                        <property name="name">FileMenu</property>
+                        <property name="label" translatable="yes">_File</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="New">
+                        <property name="name">New</property>
+                        <property name="tooltip" translatable="yes">Create a new file</property>
+                        <property name="stock_id">gtk-new</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="Open">
+                        <property name="name">Open</property>
+                        <property name="tooltip" translatable="yes">Open a file</property>
+                        <property name="stock_id">gtk-open</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="Paste">
+                        <property name="name">Paste</property>
+                        <property name="tooltip" translatable="yes">Paste object from the Clipboard</property>
+                        <property name="stock_id">gtk-paste</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="Quit">
+                        <property name="name">Quit</property>
+                        <property name="tooltip" translatable="yes">Quit the program</property>
+                        <property name="stock_id">gtk-quit</property>
+                        <signal handler="quit_activate" name="activate"/>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="Save">
+                        <property name="name">Save</property>
+                        <property name="is_important">True</property>
+                        <property name="tooltip" translatable="yes">Save a file</property>
+                        <property name="stock_id">gtk-save</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="SaveAs">
+                        <property name="name">SaveAs</property>
+                        <property name="tooltip" translatable="yes">Save with a different name</property>
+                        <property name="stock_id">gtk-save-as</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="HelpMenu">
+                        <property name="name">HelpMenu</property>
+                        <property name="label" translatable="yes">_Help</property>
+                    </object>
+                </child>
+                <child>
+                    <object class="GtkAction" id="About">
+                        <property name="name">About</property>
+                        <property name="stock_id">gtk-about</property>
+                        <signal handler="about_activate" name="activate"/>
+                    </object>
+                    <accelerator key="F1"/>
+                </child>
+            </object>
+        </child>
+        <ui>
+          <menubar name="menubar1">
+            <menu action="FileMenu" name="FileMenu">
+              <menuitem action="New" name="New"/>
+              <menuitem action="Open" name="Open"/>
+              <menuitem action="Save" name="Save"/>
+              <menuitem action="SaveAs" name="SaveAs"/>
+              <separator/>
+              <menuitem action="Quit" name="Quit"/>
+            </menu>
+            <menu action="EditMenu">
+              <menuitem action="Copy" name="Copy"/>
+              <menuitem action="Cut" name="Cut"/>
+              <menuitem action="Paste" name="Paste"/>
+            </menu>
+            <menu action="HelpMenu" name="HelpMenu">
+              <menuitem action="About" name="About"/>
+            </menu>
+          </menubar>
+          <toolbar name="toolbar1">
+            <toolitem action="New" name="New"/>
+            <toolitem action="Open" name="Open"/>
+            <toolitem action="Save" name="Save"/>
+            <separator/>
+            <toolitem action="Copy" name="Copy"/>
+            <toolitem action="Cut" name="Cut"/>
+            <toolitem action="Paste" name="Paste"/>
+          </toolbar>
+        </ui>
+    </object>
+    <object class="GtkAboutDialog" id="aboutdialog1">
+        <property name="program-name" translatable="yes">GtkBuilder demo</property>
+         <accessibility>
+	     <relation target="window1" type="subwindow-of"/>
+	 </accessibility>
+    </object>
+    <object class="GtkWindow" id="window1">
+        <property name="default_height">250</property>
+        <property name="default_width">440</property>
+        <property name="title">GtkBuilder demo</property>
+        <child>
+            <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <child>
+                    <object constructor="uimanager" class="GtkMenuBar" id="menubar1">
+                        <property name="visible">True</property>
+	            	<child internal-child="accessible">
+	            	    <object class="AtkObject" id="a11y-menubar">
+	            	        <property name="AtkObject::accessible-name">The menubar</property>
+	            	    </object>
+	            	</child>
+	            </object>
+                    <packing>
+                        <property name="expand">False</property>
+                    </packing>
+                </child>
+                <child>
+                    <object constructor="uimanager" class="GtkToolbar" id="toolbar1">
+                        <property name="visible">True</property>
+	            	<child internal-child="accessible">
+	            	    <object class="AtkObject" id="a11y-toolbar">
+	            	        <property name="AtkObject::accessible-name">The toolbar</property>
+	            	    </object>
+	            	</child>
+                    </object>
+                    <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                    </packing>
+                </child>
+                <child>
+                    <object class="GtkScrolledWindow" id="scrolledwindow1">
+                      <property name="hscrollbar_policy">automatic</property>
+                      <property name="shadow_type">in</property>
+                      <property name="visible">True</property>
+                      <property name="vscrollbar_policy">automatic</property>
+                      <child>
+                        <object class="GtkTreeView" id="treeview1">
+                          <property name="visible">True</property>
+                          <property name="model">liststore1</property>
+                          <property name="tooltip-column">3</property>
+	            	  <child internal-child="accessible">
+	            	      <object class="AtkObject" id="a11y-treeview">
+	            	          <property name="AtkObject::accessible-name">Name list</property>
+                                  <property name="AtkObject::accessible-description">
+                                    A list of person with name, surname and age columns
+                                  </property>
+	            	      </object>
+	            	  </child>
+                          <child>
+                            <object class="GtkTreeViewColumn" id="column1">
+                              <property name="title">Name</property>
+                              <child>
+                                <object class="GtkCellRendererText" id="renderer1"/>
+                                <attributes>
+                                  <attribute name="text">0</attribute>
+                                </attributes>
+                              </child>
+                            </object>
+                          </child>
+                          <child>
+                            <object class="GtkTreeViewColumn" id="column2">
+                              <property name="title">Surname</property>
+                              <child>
+                                <object class="GtkCellRendererText" id="renderer2"/>
+                                <attributes>
+                                  <attribute name="text">1</attribute>
+                                </attributes>
+                              </child>
+                            </object>
+                          </child>
+                          <child>
+                            <object class="GtkTreeViewColumn" id="column3">
+                              <property name="title">Age</property>
+                              <child>
+                                <object class="GtkCellRendererText" id="renderer3"/>
+                                <attributes>
+                                  <attribute name="text">2</attribute>
+                                </attributes>
+                              </child>
+                            </object>
+                          </child>
+                        </object>
+                      </child>
+		    <accessibility>
+		      	<action action_name="move-cursor" description="Move the cursor to select another person."/>
+		    </accessibility>
+                    </object>
+                    <packing>
+                        <property name="position">2</property>
+                    </packing>
+                </child>
+                <child>
+                    <object class="GtkStatusbar" id="statusbar1">
+                        <property name="visible">True</property>
+                    </object>
+                    <packing>
+                        <property name="expand">False</property>
+                        <property name="position">3</property>
+                    </packing>
+                </child>
+            </object>
+        </child>
+    </object>
+</interface>
diff --git a/gtk-demo/main.pl b/gtk-demo/main.pl
index 8cc3245..b44885b 100644
--- a/gtk-demo/main.pl
+++ b/gtk-demo/main.pl
@@ -34,6 +34,7 @@ my @child1 = (
 @testgtk_demos = (
   { title => "Application main window",     filename => "appwindow.pl",     func => 'stub', }, 
   { title => "Assistant",                   filename => "assistant.pl",     func => 'stub', available => sub { Gtk2->CHECK_VERSION (2, 10, 0); } },
+  { title => "Builder",                     filename => "builder.pl",       func => 'stub', available => sub { Gtk2->CHECK_VERSION (2, 12, 0); } },
   { title => "Button Boxes",                filename => "button_box.pl",    func => 'stub', }, 
   { title => "Change Display",              filename => "changedisplay.pl", func => 'stub', }, 
   { title => "Color Selector",              filename => "colorsel.pl",      func => 'stub', }, 
commit 09ed1982d686fac6fdff01d3d85f85a8d37f35f3
Author: Thorsten Otto <thotto@users.sourceforge.net>
Date:   Tue Mar 24 18:17:16 2015 +0100

    Add Gtk2::ComboBox to gtk-demo

diff --git a/gtk-demo/combobox.pl b/gtk-demo/combobox.pl
new file mode 100644
index 0000000..5cad55c
--- /dev/null
+++ b/gtk-demo/combobox.pl
@@ -0,0 +1,352 @@
+#!/usr/bin/perl -w
+#
+# Combo boxes 
+#
+# The ComboBox widget allows to select one option out of a list.
+# The ComboBoxEntry additionally allows the user to enter a value
+# that is not in the list of options. 
+#
+# How the options are displayed is controlled by cell renderers.
+#
+
+package combobox;
+
+use strict;
+use warnings;
+use Glib ':constants';
+use Gtk2;
+#include "demo-common.h"
+
+use constant PIXBUF_COL => 0;
+use constant TEXT_COL => 1;
+
+my $window = undef;
+
+
+sub create_stock_icon_store()
+{
+  my @stock_id = (
+    'gtk-dialog-warning',
+    'gtk-stop',
+    'gtk-new',
+    'gtk-clear',
+    undef,
+    'gtk-open'    
+  );
+
+  my ($item, $pixbuf, $cellview, $iter, $store, $label);
+
+  $cellview = Gtk2::CellView->new();
+  
+  $store = Gtk2::ListStore->new('Gtk2::Gdk::Pixbuf', 'Glib::String');
+
+  for my $i (@stock_id) {
+    if ($i)
+    {
+      $pixbuf = $cellview->render_icon($i,
+                       'GTK_ICON_SIZE_BUTTON');
+      $item = Gtk2::Stock->lookup($i);
+      $label = $item->{label};
+      # strip underscores
+      $label =~ tr/_//d;
+      $iter = $store->append();
+      $store->set ($iter,
+                  PIXBUF_COL, $pixbuf,
+                  TEXT_COL, $label);
+      undef $pixbuf;
+    } else {
+      $iter = $store->append();
+      $store->set($iter,
+                  PIXBUF_COL, undef,
+                  TEXT_COL, "separator");
+    }
+  }
+
+  $cellview->destroy();
+  
+  return $store;
+}
+
+
+# A GtkCellLayoutDataFunc that demonstrates how one can control
+# sensitivity of rows. This particular function does nothing 
+# useful and just makes the second row insensitive.
+#
+sub set_sensitive()
+{
+  my ($cell_layout, $cell, $tree_model, $iter, $data) = @_;
+
+  my $path = $tree_model->get_path($iter);
+  my @indices = $path->get_indices();
+  my $sensitive = $indices[0] != 1;
+  undef $path;
+
+  $cell->set("sensitive", $sensitive);
+}
+
+
+# A GtkTreeViewRowSeparatorFunc that demonstrates how rows can be
+# rendered as separators. This particular function does nothing 
+# useful and just turns the fourth row into a separator.
+#
+sub is_separator()
+{
+  my ($model, $iter, $data) = @_;
+
+  my $path = $model->get_path($iter);
+  my @indices = $path->get_indices();
+  my $result = $indices[0] == 4;
+  undef $path;
+
+  return $result;
+}
+
+sub create_capital_store()
+{
+  my %capitals = (
+     "A - B" => [
+        "Albany", "Annapolis", "Atlanta", "Augusta", "Austin", "Baton Rouge",
+        "Bismarck", "Boise", "Boston"
+     ],
+     "C - D" => [
+        "Carson City", "Charleston", "Cheyenne", "Columbia", "Columbus",
+        "Concord", "Denver", "Des Moines", "Dover"
+     ],
+     "E - J" => [
+        "Frankfort", "Harrisburg", "Hartford", "Helena", "Honolulu",
+        "Indianapolis", "Jackson", "Jefferson City", "Juneau"
+     ],
+     "K - O" => [
+        "Lansing", "Lincoln", "Little Rock", "Madison", "Montgomery",
+        "Montpelier", "Nashville", "Oklahoma City", "Olympia"
+     ],
+     "P - S" => [
+        "Phoenix", "Pierre", "Providence", "Raleigh", "Richmond", "Sacramento",
+        "Salem", "Salt Lake City", "Santa Fe", "Springfield", "St. Paul", 
+     ],
+     "T - Z" => [
+        "Tallahassee", "Topeka", "Trenton"
+     ],
+  );
+  my $store = Gtk2::TreeStore->new('Glib::String');
+  for my $i (sort { $a cmp $b} keys %capitals ) {
+    my $iter = $store->append(undef);
+    $store->set($iter, 0, $i);
+    for my $capital (@{$capitals{$i}}) {
+       my $iter2 = $store->append($iter);
+       $store->set($iter2, 0, $capital);
+    }
+  }
+  return $store;
+}
+
+
+sub is_capital_sensitive()
+{
+  my ($cell_layout, $cell, $tree_model, $iter, $data) = @_;
+  my $sensitive = !$tree_model->iter_has_child($iter);
+  $cell->set('sensitive', $sensitive);
+}
+
+
+sub fill_combo_entry($)
+{
+  my $combo = shift;
+  $combo->append_text("One");
+  $combo->append_text("Two");
+  $combo->append_text("2\x{00bd}");
+  $combo->append_text("Three");
+}
+
+
+# A simple validating entry
+package Gtk2::MaskEntry;
+use Gtk2;
+use base qw(Gtk2::Entry);
+
+
+sub mask_entry_set_background($)
+{
+    my $entry = shift;
+    if ($entry->get('mask')) {
+       my $re = $entry->get('mask');
+       if (! ($entry->get_text() =~ $re) ) {
+          $entry->modify_base('GTK_STATE_NORMAL', Gtk2::Gdk::Color->new(65535, 60000, 60000));
+          return;
+       }
+    }
+  $entry->modify_base('GTK_STATE_NORMAL', undef);
+}
+
+sub mask_entry_changed($)
+{
+    my $editable = shift;
+    mask_entry_set_background($editable);
+}
+
+sub INIT_INSTANCE($)
+{
+  my $self = shift;
+  $self->set('mask', undef);
+}
+
+use Glib::Object::Subclass
+     'Gtk2::Entry',
+     properties => [
+        Glib::ParamSpec->string (
+           'mask',
+           '',
+           '',
+           'Glib::String',
+           [qw/readable writable/]
+        ),
+     ],
+     signals => {
+        changed => \&mask_entry_changed,
+     },
+     interfaces => [
+        'Gtk2::CellEditable',
+     ];
+
+
+sub new($@)
+{
+    my $class = shift;
+    my $self = $class->SUPER::new();
+    
+    bless $self, $class;
+
+    $self;
+}
+
+package combobox;
+
+
+sub do {  
+  my $do_widget = shift;
+  
+  if (!$window) {
+    $window = Gtk2::Window->new('GTK_WINDOW_TOPLEVEL');
+    $window->set_screen ($do_widget->get_screen)
+      if Gtk2->CHECK_VERSION (2, 2, 0);
+    $window->set_title("Combo boxes");
+
+    $window->signal_connect("destroy", sub { $window = undef; });
+    
+    $window->set_border_width(10);
+
+    my $vbox = Gtk2::VBox->new(FALSE, 2);
+    $window->add($vbox);
+
+    # A combobox demonstrating cell renderers, separators and
+    # insensitive rows 
+    #
+    my $frame = Gtk2::Frame->new("Some stock icons");
+    $vbox->pack_start($frame, FALSE, FALSE, 0);
+    
+    my $box = Gtk2::VBox->new(FALSE, 0);
+    $box->set_border_width(5);
+    $frame->add($box);
+    
+    my $model = create_stock_icon_store();
+    my $combo = Gtk2::ComboBox->new_with_model($model);
+    undef $model;
+    $box->add($combo);
+    
+    my $renderer = Gtk2::CellRendererPixbuf->new();
+    $combo->pack_start($renderer, FALSE);
+    $combo->set_attributes($renderer,
+                    "pixbuf", PIXBUF_COL);
+
+    $combo->set_cell_data_func($renderer, \&set_sensitive);
+    
+    $renderer = Gtk2::CellRendererText->new();
+    $combo->pack_start($renderer, TRUE);
+    $combo->set_attributes($renderer,
+                    "text", TEXT_COL);
+
+    $combo->set_cell_data_func($renderer, \&set_sensitive);
+
+    $combo->set_row_separator_func(\&is_separator);
+    
+    $combo->set_active(0);
+    
+    # A combobox demonstrating trees.
+    #
+    $frame = Gtk2::Frame->new("Where are we ?");
+    $vbox->pack_start($frame, FALSE, FALSE, 0);
+
+    $box = Gtk2::VBox->new(FALSE, 0);
+    $box->set_border_width(5);
+    $frame->add($box);
+    
+    $model = create_capital_store ();
+    $combo = Gtk2::ComboBox->new_with_model($model);
+    # undef $model;
+    $box->add($combo);
+
+    $renderer = Gtk2::CellRendererText->new();
+    $combo->pack_start($renderer, TRUE);
+    $combo->set_attributes($renderer,
+                    "text", 0);
+    $combo->set_cell_data_func($renderer, \&is_capital_sensitive);
+
+    my $path = Gtk2::TreePath->new_from_indices(0, 8);
+    my $iter = $model->get_iter($path);
+    undef $path;
+    $combo->set_active_iter($iter);
+
+    # A GtkComboBoxEntry with validation.
+    #
+    $frame = Gtk2::Frame->new("Editable");
+    $vbox->pack_start($frame, FALSE, FALSE, 0);
+    
+    $box = Gtk2::VBox->new(FALSE, 0);
+    $box->set_border_width(5);
+    $frame->add($box);
+    
+    $combo = undef;
+    eval {
+        $combo = Gtk2::ComboBox->text_new_with_entry();
+    };
+    eval {
+        $combo = Gtk2::ComboBoxEntry->new_text();
+    } if (!$combo);
+    fill_combo_entry($combo);
+    $box->add($combo);
+    
+    my $entry = Gtk2::MaskEntry->new();
+    $entry->set('mask', "^([0-9]*|One|Two|2\x{00bd}|Three)\$");
+     
+    $combo->remove($combo->get_child());
+    $combo->add($entry);
+  }
+
+  if (!$window->visible()) {
+      $window->show_all();
+  } else {
+      $window->destroy();
+  }
+
+  return $window;
+}
+
+
+1;
+__END__
+Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
+full list)
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by the Free
+Software Foundation; either version 2.1 of the License, or (at your option) any
+later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU Library General Public License for more
+details.
+
+You should have received a copy of the GNU Library General Public License along
+with this library; if not, write to the Free Software Foundation, Inc., 59
+Temple Place - Suite 330, Boston, MA  02111-1307  USA.
diff --git a/gtk-demo/main.pl b/gtk-demo/main.pl
index b44885b..c6642ac 100644
--- a/gtk-demo/main.pl
+++ b/gtk-demo/main.pl
@@ -38,6 +38,7 @@ my @child1 = (
   { title => "Button Boxes",                filename => "button_box.pl",    func => 'stub', }, 
   { title => "Change Display",              filename => "changedisplay.pl", func => 'stub', }, 
   { title => "Color Selector",              filename => "colorsel.pl",      func => 'stub', }, 
+  { title => "Combo boxes",                 filename => "combobox.pl",      func => 'stub', available => sub { Gtk2->CHECK_VERSION (2, 4, 0); } }, 
   { title => "Dialog and Message Boxes",    filename => "dialog.pl",        func => 'stub', }, 
   { title => "Drawing Area",                filename => "drawingarea.pl",   func => 'stub', }, 
   { title => "Images",                      filename => "images.pl",        func => 'stub', }, 
