]> Pileus Git - ~andy/gtk/commitdiff
Added column list widget GtkCList. -Jay Painter
authorJay Painter <jpaint@src.gnome.org>
Sat, 3 Jan 1998 03:31:03 +0000 (03:31 +0000)
committerJay Painter <jpaint@src.gnome.org>
Sat, 3 Jan 1998 03:31:03 +0000 (03:31 +0000)
gtk/Makefile.am
gtk/gtk.h
gtk/gtkclist.c [new file with mode: 0644]
gtk/gtkclist.h [new file with mode: 0644]
gtk/testgtk.c
gtk/testgtkrc
tests/testgtk.c
tests/testgtkrc

index 5b1018b6fae9510c6ee074579a2df81ae39c1055..ff0c18e2b501d045d34bb45234fd2b37d4d0f11d 100644 (file)
@@ -16,6 +16,7 @@ libgtk_la_SOURCES = \
        gtkbutton.c             \
        gtkcheckbutton.c        \
        gtkcheckmenuitem.c      \
+       gtkclist.c              \
        gtkcolorsel.c           \
        gtkcontainer.c          \
        gtkcurve.c              \
@@ -103,6 +104,7 @@ gtkinclude_HEADERS = \
        gtkbutton.h             \
        gtkcheckbutton.h        \
        gtkcheckmenuitem.h      \
+       gtkclist.h              \
        gtkcolorsel.h           \
        gtkcontainer.h          \
        gtkcurve.h              \
index cee10d035d7421d2abd59fcd10b395f36cb76429..dfce27528724fcdac1c015eb44ab2681791f58a0 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -31,6 +31,7 @@
 #include <gtk/gtkbutton.h>
 #include <gtk/gtkcheckbutton.h>
 #include <gtk/gtkcheckmenuitem.h>
+#include <gtk/gtkclist.h>
 #include <gtk/gtkcolorsel.h>
 #include <gtk/gtkcontainer.h>
 #include <gtk/gtkcurve.h>
diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c
new file mode 100644 (file)
index 0000000..e5b06ee
--- /dev/null
@@ -0,0 +1,2817 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, 
+ * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>                     
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include "gtkclist.h"
+
+/* the width of the column resize windows */
+#define DRAG_WIDTH  5
+
+/* minimum allowed width of a column */
+#define COLUMN_MIN_WIDTH 5
+
+/* this defigns the base grid spacing */
+#define CELL_SPACING 1
+
+/* added the horizontal space at the beginning and end of a row*/
+#define COLUMN_INSET 3
+
+
+/* gives the top pixel of the given row in context of
+ * the clist's voffset */
+#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * row) + \
+                                   ((row + 1) * CELL_SPACING) + \
+                                   (clist)->voffset)
+
+/* returns the row index from a y pixel location in the 
+ * context of the clist's voffset */
+#define ROW_FROM_YPIXEL(clist, y)  ((y - (clist)->voffset) / \
+                                   ((clist)->row_height + CELL_SPACING))
+
+/* gives the left pixel of the given column in context of
+ * the clist's hoffset */
+#define COLUMN_LEFT_YPIXEL(clist, column)  ((clist)->column[(column)].area.x + \
+                                           (clist)->hoffset)
+
+/* returns the column index from a x pixel location in the 
+ * context of the clist's hoffset */
+static inline gint
+COLUMN_FROM_XPIXEL (GtkCList * clist,
+                   gint x)
+{
+  gint i, cx;
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      cx = clist->column[i].area.x + clist->hoffset;
+
+      if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
+         x <= (cx + clist->column[i].area.width + COLUMN_INSET))
+       return i;
+    }
+
+  /* no match */
+  return -1;
+}
+
+/* returns the top pixel of the given row in the context of
+ * the list height */
+#define ROW_TOP(clist, row)        (((clist)->row_height + CELL_SPACING) * (row))
+
+/* returns the left pixel of the given column in the context of
+ * the list width */
+#define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
+
+/* returns the total height of the list */
+#define LIST_HEIGHT(clist)         (((clist)->row_height * ((clist)->rows)) + \
+                                   (CELL_SPACING * ((clist)->rows + 1)))
+
+/* returns the total width of the list */
+#define LIST_WIDTH(clist)          ((clist)->column[(clist)->columns - 1].area.x + \
+                                   (clist)->column[(clist)->columns - 1].area.width + \
+                                   COLUMN_INSET + CELL_SPACING)
+
+
+/* Signals */
+enum
+{
+  SELECT_ROW,
+  UNSELECT_ROW,
+  CLICK_COLUMN,
+  LAST_SIGNAL
+};
+
+typedef void (*GtkCListSignal1) (GtkObject * object,
+                                gint arg1,
+                                gint arg2,
+                                GdkEventButton * arg3,
+                                gpointer data);
+
+typedef void (*GtkCListSignal2) (GtkObject * object,
+                                gint arg1,
+                                gpointer data);
+
+
+/* GtkCList Methods */
+static void gtk_clist_class_init (GtkCListClass * klass);
+static void gtk_clist_init (GtkCList * clist);
+
+static gint gtk_clist_row_isvisable (GtkCList * clist,
+                                    gint row);
+
+static void gtk_clist_draw_row (GtkCList * clist,
+                               GdkRectangle * area,
+                               gint row,
+                               GtkCListRow * clist_row);
+
+static void gtk_clist_draw_rows (GtkCList * clist,
+                                GdkRectangle * area);
+
+static gint gtk_clist_get_selection_info (GtkCList * clist,
+                                         gint x,
+                                         gint y,
+                                         gint * row,
+                                         gint * column);
+
+static void gtk_clist_real_select_row (GtkCList * clist,
+                                      gint row,
+                                      gint column,
+                                      GdkEventButton * event);
+static void gtk_clist_real_unselect_row (GtkCList * clist,
+                                        gint row,
+                                        gint column,
+                                        GdkEventButton * event);
+
+static void gtk_clist_size_allocate_title_buttons (GtkCList * clist);
+static void gtk_clist_size_allocate_columns (GtkCList * clist);
+
+
+/* GtkObject Methods */
+static void gtk_clist_destroy (GtkObject * object);
+
+
+/* GtkWidget Methods */
+static void gtk_clist_realize (GtkWidget * widget);
+static void gtk_clist_unrealize (GtkWidget * widget);
+static void gtk_clist_map (GtkWidget * widget);
+static void gtk_clist_unmap (GtkWidget * widget);
+static void gtk_clist_draw (GtkWidget * widget,
+                           GdkRectangle * area);
+static gint gtk_clist_expose (GtkWidget * widget,
+                             GdkEventExpose * event);
+static gint gtk_clist_button_press (GtkWidget * widget,
+                                   GdkEventButton * event);
+
+static void gtk_clist_size_request (GtkWidget * widget,
+                                   GtkRequisition * requisition);
+static void gtk_clist_size_allocate (GtkWidget * widget,
+                                    GtkAllocation * allocation);
+
+
+/* GtkContainer Methods */
+static void gtk_clist_foreach (GtkContainer * container,
+                              GtkCallback callback,
+                              gpointer callback_data);
+
+
+/* Buttons */
+static void gtk_clist_column_button_realize (GtkWidget * widget,
+                                            gpointer data);
+static void gtk_clist_column_button_clicked (GtkWidget * widget,
+                                            gpointer data);
+
+
+/* Scrollbars */
+static void gtk_clist_adjust_scrollbars (GtkCList * clist);
+static void gtk_clist_vadjustment_changed (GtkAdjustment * adjustment,
+                                          gpointer data);
+static void gtk_clist_vadjustment_value_changed (GtkAdjustment * adjustment,
+                                                gpointer data);
+static void gtk_clist_hadjustment_changed (GtkAdjustment * adjustment,
+                                          gpointer data);
+static void gtk_clist_hadjustment_value_changed (GtkAdjustment * adjustment,
+                                                gpointer data);
+
+
+/* Memory Allocation/Distruction Routines */
+static GtkCListColumn *gtk_clist_columns_new (GtkCList * clist);
+
+static void gtk_clist_column_title_new (GtkCList * clist,
+                                       gint column,
+                                       gchar * title);
+static void gtk_clist_columns_delete (GtkCList * clist);
+
+static GtkCListRow *gtk_clist_row_new (GtkCList * clist);
+
+static void gtk_clist_row_delete (GtkCList * clist,
+                                 GtkCListRow * clist_row);
+static void gtk_clist_cell_empty (GtkCList * clist,
+                                 GtkCListRow * clist_row,
+                                 gint column);
+static void gtk_clist_cell_set_text (GtkCList * clist,
+                                    GtkCListRow * clist_row,
+                                    gint column,
+                                    gchar * text);
+static void gtk_clist_cell_set_pixmap (GtkCList * clist,
+                                      GtkCListRow * clist_row,
+                                      gint column,
+                                      GdkPixmap * pixmap,
+                                      GdkBitmap * mask);
+static void gtk_clist_cell_set_pixtext (GtkCList * clist,
+                                       GtkCListRow * clist_row,
+                                       gint column,
+                                       gchar * text,
+                                       guint8 spacing,
+                                       GdkPixmap * pixmap,
+                                       GdkBitmap * mask);
+
+/* Signals */
+static void gtk_clist_marshal_signal_1 (GtkObject * object,
+                                       GtkSignalFunc func,
+                                       gpointer func_data,
+                                       GtkArg * args);
+static void gtk_clist_marshal_signal_2 (GtkObject * object,
+                                       GtkSignalFunc func,
+                                       gpointer func_data,
+                                       GtkArg * args);
+
+
+static GtkContainerClass *parent_class = NULL;
+static gint clist_signals[LAST_SIGNAL] = {0};
+
+
+guint
+gtk_clist_get_type ()
+{
+  static guint clist_type = 0;
+
+  if (!clist_type)
+    {
+      GtkTypeInfo clist_info =
+      {
+       "GtkCList",
+       sizeof (GtkCList),
+       sizeof (GtkCListClass),
+       (GtkClassInitFunc) gtk_clist_class_init,
+       (GtkObjectInitFunc) gtk_clist_init,
+       (GtkArgFunc) NULL,
+      };
+
+      clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info);
+    }
+
+  return clist_type;
+}
+
+static void
+gtk_clist_class_init (GtkCListClass * klass)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  GtkContainerClass *container_class;
+
+  object_class = (GtkObjectClass *) klass;
+  widget_class = (GtkWidgetClass *) klass;
+  container_class = (GtkContainerClass *) klass;
+
+  parent_class = gtk_type_class (gtk_container_get_type ());
+
+  clist_signals[SELECT_ROW] =
+    gtk_signal_new ("select_row",
+                   GTK_RUN_LAST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
+                   gtk_clist_marshal_signal_1,
+           GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
+  clist_signals[UNSELECT_ROW] =
+    gtk_signal_new ("unselect_row",
+                   GTK_RUN_LAST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
+                   gtk_clist_marshal_signal_1,
+           GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
+  clist_signals[CLICK_COLUMN] =
+    gtk_signal_new ("click_column",
+                   GTK_RUN_LAST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
+                   gtk_clist_marshal_signal_2,
+                   GTK_TYPE_NONE, 1, GTK_TYPE_INT);
+
+  gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
+
+  object_class->destroy = gtk_clist_destroy;
+
+  widget_class->realize = gtk_clist_realize;
+  widget_class->unrealize = gtk_clist_unrealize;
+  widget_class->map = gtk_clist_map;
+  widget_class->unmap = gtk_clist_unmap;
+  widget_class->draw = gtk_clist_draw;
+  widget_class->button_press_event = gtk_clist_button_press;
+  widget_class->expose_event = gtk_clist_expose;
+  widget_class->size_request = gtk_clist_size_request;
+  widget_class->size_allocate = gtk_clist_size_allocate;
+
+  container_class->add = NULL;
+  container_class->remove = NULL;
+  container_class->foreach = gtk_clist_foreach;
+
+  klass->select_row = gtk_clist_real_select_row;
+  klass->unselect_row = gtk_clist_real_unselect_row;
+  klass->click_column = NULL;
+}
+
+static void
+gtk_clist_marshal_signal_1 (GtkObject * object,
+                           GtkSignalFunc func,
+                           gpointer func_data,
+                           GtkArg * args)
+{
+  GtkCListSignal1 rfunc;
+
+  rfunc = (GtkCListSignal1) func;
+
+  (*rfunc) (object, GTK_VALUE_INT (args[0]),
+           GTK_VALUE_INT (args[1]),
+           GTK_VALUE_POINTER (args[2]),
+           func_data);
+}
+
+static void
+gtk_clist_marshal_signal_2 (GtkObject * object,
+                           GtkSignalFunc func,
+                           gpointer func_data,
+                           GtkArg * args)
+{
+  GtkCListSignal2 rfunc;
+
+  rfunc = (GtkCListSignal2) func;
+
+  (*rfunc) (object, GTK_VALUE_INT (args[0]),
+           func_data);
+}
+
+static void
+gtk_clist_init (GtkCList * clist)
+{
+  clist->flags = 0;
+
+  GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
+  GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
+
+  clist->rows = 0;
+  clist->row_center_offset = 0;
+  clist->row_height = 0;
+  clist->row_list = NULL;
+  clist->row_list_end = NULL;
+
+  clist->columns = 0;
+
+  clist->column_title_area.x = 0;
+  clist->column_title_area.y = 0;
+  clist->column_title_area.width = 0;
+  clist->column_title_area.height = 0;
+
+  clist->clist_window = NULL;
+  clist->clist_window_width = 0;
+  clist->clist_window_height = 0;
+
+  clist->hoffset = 0;
+  clist->voffset = 0;
+
+  clist->shadow_type = GTK_SHADOW_IN;
+  clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
+  clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
+
+  clist->cursor_drag = NULL;
+  clist->xor_gc = NULL;
+  clist->fg_gc = NULL;
+  clist->bg_gc = NULL;
+  clist->x_drag = 0;
+
+  clist->selection_mode = GTK_SELECTION_SINGLE;
+}
+
+GtkWidget *
+gtk_clist_new (int columns,
+              gchar * titles[])
+{
+  int i;
+  GtkCList *clist;
+  GtkAdjustment *adjustment;
+
+  /* sanity check */
+  if (columns < 1 || titles == NULL)
+    return NULL;
+
+  clist = gtk_type_new (gtk_clist_get_type ());
+
+  /* initalize memory chunks */
+  clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
+                                          sizeof (GtkCListRow),
+                                          1024, G_ALLOC_AND_FREE);
+  clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
+                                          sizeof (GtkCell) * columns,
+                                          1024, G_ALLOC_AND_FREE);
+
+  /* set number of columns, allocate memory */
+  clist->columns = columns;
+  clist->column = gtk_clist_columns_new (clist);
+
+  /* create column button and connect signals */
+  for (i = 0; i < columns; i++)
+    {
+      clist->column[i].button = gtk_button_new ();
+      gtk_widget_set_parent (clist->column[i].button, GTK_WIDGET (clist));
+
+      gtk_signal_connect_after (GTK_OBJECT (clist->column[i].button),
+                               "realize",
+                               (GtkSignalFunc) gtk_clist_column_button_realize,
+                               (gpointer) clist);
+
+      gtk_signal_connect (GTK_OBJECT (clist->column[i].button),
+                         "clicked",
+                         (GtkSignalFunc) gtk_clist_column_button_clicked,
+                         (gpointer) clist);
+
+      /* set column title */
+      gtk_clist_set_column_title (clist, i, titles[i]);
+
+      clist->column[i].width = 
+       gdk_string_width (GTK_WIDGET (clist)->style->font, clist->column[i].title);
+
+      gtk_widget_show (clist->column[i].button);
+    }
+
+
+  /* create and connect scrollbars */
+  clist->vscrollbar = gtk_vscrollbar_new (NULL);
+  adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
+
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_clist_vadjustment_changed,
+                     (gpointer) clist);
+
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_clist_vadjustment_value_changed,
+                     (gpointer) clist);
+
+  gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
+  gtk_widget_show (clist->vscrollbar);
+
+  clist->hscrollbar = gtk_hscrollbar_new (NULL);
+  adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
+
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_clist_hadjustment_changed,
+                     (gpointer) clist);
+
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_clist_hadjustment_value_changed,
+                     (gpointer) clist);
+
+  gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
+  gtk_widget_show (clist->hscrollbar);
+
+  return GTK_WIDGET (clist);
+}
+
+void
+gtk_clist_set_border (GtkCList * clist,
+                     GtkShadowType border)
+{
+  g_return_if_fail (clist != NULL);
+
+  clist->shadow_type = border;
+
+  if (GTK_WIDGET_VISIBLE (clist))
+    gtk_widget_queue_resize (GTK_WIDGET (clist));
+}
+
+void
+gtk_clist_set_selection_mode (GtkCList * clist,
+                             GtkSelectionMode mode)
+{
+  g_return_if_fail (clist != NULL);
+
+  clist->selection_mode = mode;
+}
+
+void
+gtk_clist_freeze (GtkCList * clist)
+{
+  g_return_if_fail (clist != NULL);
+
+  GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
+}
+
+void
+gtk_clist_thaw (GtkCList * clist)
+{
+  g_return_if_fail (clist != NULL);
+
+  GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
+
+  gtk_clist_adjust_scrollbars (clist);
+  gtk_clist_draw_rows (clist, NULL);
+}
+
+
+void
+gtk_clist_set_column_title (GtkCList * clist,
+                           gint column,
+                           gchar * title)
+{
+  GtkWidget *old_widget;
+  GtkWidget *alignment;
+  GtkWidget *label;
+
+  g_return_if_fail (clist != NULL);
+
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  gtk_clist_column_title_new (clist, column, title);
+
+  /* remove and destroy the old widget */
+  old_widget = GTK_BUTTON (clist->column[column].button)->child;
+  if (old_widget)
+    {
+      gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
+      gtk_widget_destroy (old_widget);
+    }
+
+  switch (clist->column[column].justification)
+    {
+    case GTK_JUSTIFY_LEFT:
+      alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
+      break;
+
+    case GTK_JUSTIFY_RIGHT:
+      alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
+      break;
+
+    case GTK_JUSTIFY_CENTER:
+      alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+      break;
+
+    case GTK_JUSTIFY_FILL:
+      alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+      break;
+
+    default:
+      break;
+    }
+
+  if (alignment)
+    {
+      label = gtk_label_new (clist->column[column].title);
+      gtk_container_add (GTK_CONTAINER (alignment), label);
+      gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
+      gtk_widget_show (label);
+      gtk_widget_show (alignment);
+    }
+}
+
+void
+gtk_clist_set_column_widget (GtkCList * clist,
+                            gint column,
+                            GtkWidget * widget)
+{
+  GtkWidget *old_widget;
+
+  g_return_if_fail (clist != NULL);
+
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  gtk_clist_column_title_new (clist, column, NULL);
+
+  /* remove and destroy the old widget */
+  old_widget = GTK_BUTTON (clist->column[column].button)->child;
+  if (old_widget)
+    {
+      gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
+      gtk_widget_destroy (old_widget);
+    }
+
+  /* add and show the widget */
+  if (widget)
+    {
+      gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
+      gtk_widget_show (widget);
+    }
+}
+
+void
+gtk_clist_set_column_justification (GtkCList * clist,
+                                   gint column,
+                                   GtkJustification justification)
+{
+  GtkWidget *alignment;
+
+  g_return_if_fail (clist != NULL);
+
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist->column[column].justification = justification;
+
+  /* change the alinment of the button title if it's not a
+   * custom widget */
+  if (clist->column[column].title)
+    {
+      alignment = GTK_BUTTON (clist->column[column].button)->child;
+
+      switch (clist->column[column].justification)
+       {
+       case GTK_JUSTIFY_LEFT:
+         gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
+         break;
+
+       case GTK_JUSTIFY_RIGHT:
+         gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
+         break;
+
+       case GTK_JUSTIFY_CENTER:
+         gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
+         break;
+
+       case GTK_JUSTIFY_FILL:
+         gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (!GTK_CLIST_FROZEN (clist))
+    gtk_clist_draw_rows (clist, NULL);
+}
+
+void
+gtk_clist_set_column_width (GtkCList * clist,
+                           gint column,
+                           gint width)
+{
+  g_return_if_fail (clist != NULL);
+
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist->column[column].width = width;
+
+  gtk_clist_size_allocate_title_buttons (clist);
+
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      gtk_clist_adjust_scrollbars (clist);
+      gtk_clist_draw_rows (clist, NULL);
+    }
+}
+
+void
+gtk_clist_set_row_height (GtkCList * clist,
+                         gint height)
+{
+  gint text_height;
+
+  g_return_if_fail (clist != NULL);
+
+  if (height > 0)
+    clist->row_height = height;
+  else
+    return;
+
+  GTK_CLIST_SET_FLAGS (clist, CLIST_ROW_HEIGHT_SET);
+
+  text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
+                         GTK_WIDGET (clist) ->style->font->descent + 1);
+  clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
+
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      gtk_clist_adjust_scrollbars (clist);
+      gtk_clist_draw_rows (clist, NULL);
+    }
+}
+
+void
+gtk_clist_moveto (GtkCList * clist,
+                 gint row,
+                 gint column,
+                 gfloat row_align,
+                 gfloat col_align)
+{
+  gint x, y;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  /* adjust vertical scrollbar */
+  x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height - 
+                                          (clist->row_height + 2 * CELL_SPACING)));
+
+  if (x < 0)
+    GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
+  else if (x > LIST_HEIGHT (clist) - clist->clist_window_height)
+    GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - 
+      clist->clist_window_height;
+  else
+    GTK_RANGE (clist->vscrollbar)->adjustment->value = x;
+
+  gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
+                          "value_changed");
+
+  /* adjust horizontal scrollbar */
+  y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width - 
+                                                 clist->column[column].area.width + 
+                                                 2 * (CELL_SPACING + COLUMN_INSET)));
+
+  if (y < 0)
+    GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0;
+  else if (y > LIST_WIDTH (clist) - clist->clist_window_width)
+    GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - 
+      clist->clist_window_width;
+  else
+    GTK_RANGE (clist->hscrollbar)->adjustment->value = y;
+
+  gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
+                          "value_changed");
+
+}
+
+void
+gtk_clist_set_text (GtkCList * clist,
+                   gint row,
+                   gint column,
+                   gchar * text)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+
+  /* if text is null, then the cell is empty */
+  if (text)
+    gtk_clist_cell_set_text (clist, clist_row, column, text);
+  else
+    gtk_clist_cell_empty (clist, clist_row, column);
+
+  /* redraw the list if it's not frozen */
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      if (gtk_clist_row_isvisable (clist, row))
+       gtk_clist_draw_row (clist, NULL, row, clist_row);
+    }
+}
+
+void
+gtk_clist_set_pixmap (GtkCList * clist,
+                     gint row,
+                     gint column,
+                     GdkPixmap * pixmap,
+                     GdkBitmap * mask)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  
+  gdk_pixmap_ref (pixmap);
+  gdk_pixmap_ref (mask);
+  gtk_clist_cell_set_pixmap (clist, clist_row, column, pixmap, mask);
+
+  /* redraw the list if it's not frozen */
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      if (gtk_clist_row_isvisable (clist, row))
+       gtk_clist_draw_row (clist, NULL, row, clist_row);
+    }
+}
+
+void
+gtk_clist_set_pixtext (GtkCList * clist,
+                      gint row,
+                      gint column,
+                      gchar * text,
+                      guint8 spacing,
+                      GdkPixmap * pixmap,
+                      GdkBitmap * mask)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  
+  gdk_pixmap_ref (pixmap);
+  gdk_pixmap_ref (mask);
+  gtk_clist_cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
+
+  /* redraw the list if it's not frozen */
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      if (gtk_clist_row_isvisable (clist, row))
+       gtk_clist_draw_row (clist, NULL, row, clist_row);
+    }
+}
+
+void
+gtk_clist_set_foreground (GtkCList * clist,
+                         gint row,
+                         GdkColor * color)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (color != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  clist_row->foreground = *color;
+
+  if (!GTK_CLIST_FROZEN (clist))
+    if (gtk_clist_row_isvisable (clist, row))
+      gtk_clist_draw_row (clist, NULL, row, clist_row);
+}
+
+void gtk_clist_set_background (GtkCList * clist,
+                              gint row,
+                              GdkColor * color)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (color != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  clist_row->background = *color;
+
+  if (!GTK_CLIST_FROZEN (clist))
+    if (gtk_clist_row_isvisable (clist, row))
+      gtk_clist_draw_row (clist, NULL, row, clist_row);
+}
+
+void
+gtk_clist_set_shift (GtkCList * clist,
+                    gint row,
+                    gint column,
+                    gint verticle,
+                    gint horizontal)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+
+  clist_row->cell[column].verticle = verticle;
+  clist_row->cell[column].horizontal = horizontal;
+
+  if (!GTK_CLIST_FROZEN (clist))
+    if (gtk_clist_row_isvisable (clist, row))
+      gtk_clist_draw_row (clist, NULL, row, clist_row);
+}
+
+gint
+gtk_clist_append (GtkCList * clist,
+                 gchar * text[])
+{
+  gint i;
+  GtkCListRow *clist_row;
+
+  g_return_val_if_fail (clist != NULL, -1);
+
+  clist_row = gtk_clist_row_new (clist);
+  clist->rows++;
+
+  /* keeps track of the end of the list so the list 
+   * doesn't have to be traversed every time a item is added */
+  if (!clist->row_list)
+    {
+      clist->row_list = g_list_append (clist->row_list, clist_row);
+      clist->row_list_end = clist->row_list;
+
+      /* check the selection mode to see if we should select
+       * the first row automaticly */
+      switch (clist->selection_mode)
+       {
+       case GTK_SELECTION_BROWSE:
+         gtk_clist_select_row (clist, 0, -1);
+         break;
+
+       default:
+         break;
+       }
+    }
+  else
+    clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
+
+  /* set the text in the row's columns */
+  for (i = 0; i < clist->columns; i++)
+    if (text[i])
+      gtk_clist_cell_set_text (clist, clist_row, i, text[i]);
+
+  /* redraw the list if it's not frozen */
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      gtk_clist_adjust_scrollbars (clist);
+
+      if (gtk_clist_row_isvisable (clist, clist->rows - 1))
+       gtk_clist_draw_rows (clist, NULL);
+    }
+
+  /* return index of the row */
+  return clist->rows - 1;
+}
+
+void
+gtk_clist_insert (GtkCList * clist,
+                 gint row,
+                 gchar * text[])
+{
+  gint i;
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (text != NULL);
+
+  /*
+   * return if out of bounds
+   */
+  if (row < 0 || row > (clist->rows - 1))
+    return;
+
+  /* create the row */
+  clist_row = gtk_clist_row_new (clist);
+
+  /* reset the row end pointer if we're inserting at the
+   * end of the list */
+  if (row == clist->rows)
+    clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
+  else
+    clist->row_list = g_list_insert (clist->row_list, clist_row, row);
+
+  clist->rows++;
+
+  /* set the text in the row's columns */
+  for (i = 0; i < clist->columns; i++)
+    if (text[i])
+      gtk_clist_cell_set_text (clist, clist_row, i, text[i]);
+
+  /* redraw the list if it isn't frozen */
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      gtk_clist_adjust_scrollbars (clist);
+
+      if (gtk_clist_row_isvisable (clist, row))
+       gtk_clist_draw_rows (clist, NULL);
+    }
+}
+
+void
+gtk_clist_remove (GtkCList * clist,
+                 gint row)
+{
+  GList *list;
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  /* return if out of bounds */
+  if (row < 0 || row > (clist->rows - 1))
+    return;
+
+  /* get the row we're going to delete */
+  list = g_list_nth (clist->row_list, row);
+  clist_row = list->data;
+
+  /* reset the row end pointer if we're removing at the
+   * end of the list */
+  if (row == clist->rows - 1)
+    clist->row_list_end = list->prev;
+
+  clist->row_list = g_list_remove (clist->row_list, clist_row);
+  clist->rows--;
+  gtk_clist_row_delete (clist, clist_row);
+
+  /* redraw the row if it isn't frozen */
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      gtk_clist_adjust_scrollbars (clist);
+
+      if (gtk_clist_row_isvisable (clist, row))
+       gtk_clist_draw_rows (clist, NULL);
+    }
+}
+
+void
+gtk_clist_clear (GtkCList * clist)
+{
+  GList *list;
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  list = clist->row_list;
+  while (list)
+    {
+      clist_row = list->data;
+      list = list->next;
+
+      gtk_clist_row_delete (clist, clist_row);
+    }
+  g_list_free (clist->row_list);
+
+  clist->row_list = NULL;
+  clist->row_list_end = NULL;
+  clist->voffset = 0;
+  clist->rows = 0;
+
+  /* zero-out the scrollbars */
+  GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
+  gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
+
+  if (!GTK_CLIST_FROZEN (clist))
+    {
+      gtk_clist_adjust_scrollbars (clist);
+      gtk_clist_draw_rows (clist, NULL);
+    }
+}
+
+void
+gtk_clist_set_row_data (GtkCList * clist,
+                       gint row,
+                       gpointer data)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row > (clist->rows - 1))
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  clist_row->data = data;
+
+  /*
+   * re-send the selected signal if data is changed/added
+   * so the application can respond to the new data -- 
+   * this could be questionable behavior
+   */
+  if (clist_row->state == GTK_STATE_SELECTED)
+    gtk_clist_select_row (clist, 0, 0);
+}
+
+gpointer
+gtk_clist_get_row_data (GtkCList * clist,
+                       gint row)
+{
+  GtkCListRow *clist_row;
+
+  g_return_val_if_fail (clist != NULL, NULL);
+
+  if (row < 0 || row > (clist->rows - 1))
+    return NULL;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  return clist_row->data;
+}
+
+void
+gtk_clist_select_row (GtkCList * clist,
+                     gint row,
+                     gint column)
+{
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+
+  if (column < -1 || column >= clist->columns)
+    return;
+
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], row, column, NULL);
+}
+
+void
+gtk_clist_unselect_row (GtkCList * clist,
+                       gint row,
+                       gint column)
+{
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+
+  if (column < -1 || column >= clist->columns)
+    return;
+
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], row, column, NULL);
+}
+
+static gint
+gtk_clist_row_isvisable (GtkCList * clist,
+                        gint row)
+{
+  g_return_val_if_fail (clist != NULL, 0);
+
+  if (row < 0 || row >= clist->rows)
+    return 0;
+
+  if (clist->row_height == 0)
+    return 0;
+
+  if (row < ROW_FROM_YPIXEL (clist, 0))
+    return 0;
+
+  if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
+    return 0;
+
+  return 1;
+}
+
+GtkAdjustment *
+gtk_clist_get_vadjustment (GtkCList * clist)
+{
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
+
+  return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
+}
+
+GtkAdjustment *
+gtk_clist_get_hadjustment (GtkCList * clist)
+{
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
+
+  return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
+}
+
+void
+gtk_clist_set_policy (GtkCList * clist,
+                     GtkPolicyType vscrollbar_policy,
+                     GtkPolicyType hscrollbar_policy)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (clist->vscrollbar_policy != vscrollbar_policy)
+    {
+      clist->vscrollbar_policy = vscrollbar_policy;
+
+      if (GTK_WIDGET (clist)->parent)
+       gtk_widget_queue_resize (GTK_WIDGET (clist));
+    }
+
+  if (clist->hscrollbar_policy != hscrollbar_policy)
+    {
+      clist->hscrollbar_policy = hscrollbar_policy;
+
+      if (GTK_WIDGET (clist)->parent)
+       gtk_widget_queue_resize (GTK_WIDGET (clist));
+    }
+}
+
+static void
+gtk_clist_destroy (GtkObject * object)
+{
+  gint i;
+  GtkCList *clist;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_CLIST (object));
+
+  clist = GTK_CLIST (object);
+
+  /* freeze the list */
+  GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
+
+  /* destroy the scrollbars */
+  gtk_widget_destroy (clist->vscrollbar);
+  gtk_widget_destroy (clist->hscrollbar);
+
+  /* get rid of all the rows */
+  gtk_clist_clear (clist);
+
+  /* get rid of all the column buttons */
+  for (i = 0; i < clist->columns; i++)
+    gtk_widget_destroy (clist->column[i].button);
+
+  gtk_clist_columns_delete (clist);
+
+  /* get rid of the memory chunks */
+  g_mem_chunk_destroy (clist->cell_mem_chunk);
+  g_mem_chunk_destroy (clist->row_mem_chunk);
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+gtk_clist_realize (GtkWidget * widget)
+{
+  GtkCList *clist;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GdkGCValues values;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+
+  clist = GTK_CLIST (widget);
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_EXPOSURE_MASK |
+                           GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK |
+                           GDK_KEY_PRESS_MASK);
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+
+  /* main window */
+  widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, clist);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+
+  /* column-title window */
+  clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
+  gdk_window_set_user_data (clist->title_window, clist);
+
+  gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
+  gdk_window_show (clist->title_window);
+
+  /* clist-window */
+  clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
+  gdk_window_set_user_data (clist->clist_window, clist);
+
+  gdk_window_set_background (clist->clist_window, &widget->style->white);
+  gdk_window_show (clist->clist_window);
+  gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
+                      &clist->clist_window_height);
+
+  /* cursor's and GC's */
+  clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+
+  clist->fg_gc = gdk_gc_new (widget->window);
+  clist->bg_gc = gdk_gc_new (widget->window);
+
+  values.foreground = widget->style->white;
+  values.function = GDK_XOR;
+  values.subwindow_mode = GDK_INCLUDE_INFERIORS;
+  clist->xor_gc = gdk_gc_new_with_values (widget->window,
+                                         &values,
+                                         GDK_GC_FOREGROUND |
+                                         GDK_GC_FUNCTION |
+                                         GDK_GC_SUBWINDOW);
+
+  /* text properties */
+  if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
+    {
+      clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
+      clist->row_center_offset = widget->style->font->ascent + 1.5;
+    }
+}
+
+static void
+gtk_clist_unrealize (GtkWidget * widget)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+
+  clist = GTK_CLIST (widget);
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED);
+  GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
+
+  gdk_cursor_destroy (clist->cursor_drag);
+  gdk_gc_destroy (clist->xor_gc);
+  gdk_gc_destroy (clist->fg_gc);
+  gdk_gc_destroy (clist->bg_gc);
+
+  gtk_style_detach (widget->style);
+
+  gdk_window_destroy (clist->clist_window);
+  gdk_window_destroy (clist->title_window);
+  gdk_window_set_user_data (widget->window, NULL);
+  gdk_window_destroy (widget->window);
+
+  widget->window = NULL;
+  clist->clist_window = NULL;
+  clist->title_window = NULL;
+  clist->cursor_drag = NULL;
+  clist->xor_gc = NULL;
+  clist->fg_gc = NULL;
+  clist->bg_gc = NULL;
+}
+
+static void
+gtk_clist_map (GtkWidget * widget)
+{
+  gint i;
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+
+  clist = GTK_CLIST (widget);
+
+  if (!GTK_WIDGET_MAPPED (widget))
+    {
+      GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+
+      gdk_window_show (widget->window);
+      gdk_window_show (clist->title_window);
+      gdk_window_show (clist->clist_window);
+
+      /* map column buttons*/
+      for (i = 0; i < clist->columns; i++)
+       if (GTK_WIDGET_VISIBLE (clist->column[i].button) &&
+           !GTK_WIDGET_MAPPED (clist->column[i].button))
+         gtk_widget_map (clist->column[i].button);
+      
+      /* map vscrollbars */
+      if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
+         !GTK_WIDGET_MAPPED (clist->vscrollbar))
+       gtk_widget_map (clist->vscrollbar);
+
+      if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
+         !GTK_WIDGET_MAPPED (clist->hscrollbar))
+       gtk_widget_map (clist->hscrollbar);
+
+      /* unfreeze the list */
+      GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
+    }
+}
+
+static void
+gtk_clist_unmap (GtkWidget * widget)
+{
+  gint i;
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+
+  clist = GTK_CLIST (widget);
+
+  if (GTK_WIDGET_MAPPED (widget))
+    {
+      GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+
+      gdk_window_hide (clist->clist_window);
+      gdk_window_hide (clist->title_window);
+      gdk_window_hide (widget->window);
+
+      /* unmap scrollbars */
+      if (GTK_WIDGET_MAPPED (clist->vscrollbar))
+       gtk_widget_unmap (clist->vscrollbar);
+
+      if (GTK_WIDGET_MAPPED (clist->hscrollbar))
+       gtk_widget_unmap (clist->hscrollbar);
+
+      /* unmap column buttons */
+      for (i = 0; i < clist->columns; i++)
+       if (GTK_WIDGET_MAPPED (clist->column[i].button))
+         gtk_widget_unmap (clist->column[i].button);
+
+      /* freeze the list */
+      GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
+    }
+}
+
+static void
+gtk_clist_draw_row (GtkCList * clist,
+                   GdkRectangle * area,
+                   gint row,
+                   GtkCListRow * clist_row)
+{
+  GtkWidget *widget;
+  GdkGC *fg_gc, *bg_gc;
+  GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
+   *rect;
+  gint i, offset = 0, width, height, pixmap_width = 0;
+  gint xsrc, ysrc, xdest, ydest;
+
+  g_return_if_fail (clist != NULL);
+
+  /* bail now if we arn't drawable yet */
+  if (!GTK_WIDGET_DRAWABLE (clist))
+    return;
+
+  if (row < 0 || row >= clist->rows)
+    return;
+
+  widget = GTK_WIDGET (clist);
+
+  /* if the function is passed the pointer to the row instead of null,
+   * it avoids this expensive lookup */
+  if (!clist_row)
+    clist_row = (g_list_nth (clist->row_list, row))->data;
+
+  /* rectangle of the entire row */
+  row_rectangle.x = 0;
+  row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
+  row_rectangle.width = clist->clist_window_width;
+  row_rectangle.height = clist->row_height;
+
+  /* rectangle of the cell spacing above the row */
+  cell_rectangle.x = 0;
+  cell_rectangle.y = row_rectangle.y - CELL_SPACING;
+  cell_rectangle.width = row_rectangle.width;
+  cell_rectangle.height = CELL_SPACING;
+
+  /* rectangle used to clip drawing operations, it's y and height
+   * positions only need to be set once, so we set them once here. 
+   * the x and width are set withing the drawing loop below once per
+   * column */
+  clip_rectangle.y = row_rectangle.y;
+  clip_rectangle.height = row_rectangle.height;
+
+  /* select GC for background rectangle */
+  if (clist_row->state == GTK_STATE_SELECTED)
+    {
+      fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
+      bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
+    }
+  else
+    {
+      gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
+      gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
+
+      fg_gc = clist->fg_gc;
+      bg_gc = clist->bg_gc;
+    }
+
+
+  if (area)
+    {
+      if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
+       gdk_window_clear_area (clist->clist_window,
+                              intersect_rectangle.x,
+                              intersect_rectangle.y,
+                              intersect_rectangle.width,
+                              intersect_rectangle.height);
+
+      /* the last row has to clear it's bottom cell spacing too */
+      if (clist_row == clist->row_list_end->data)
+       {
+         cell_rectangle.y += clist->row_height + CELL_SPACING;
+
+         if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
+           gdk_window_clear_area (clist->clist_window,
+                                  intersect_rectangle.x,
+                                  intersect_rectangle.y,
+                                  intersect_rectangle.width,
+                                  intersect_rectangle.height);
+       }         
+
+      if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
+       return;
+
+      gdk_draw_rectangle (clist->clist_window,
+                         bg_gc,
+                         TRUE,
+                         intersect_rectangle.x,
+                         intersect_rectangle.y,
+                         intersect_rectangle.width,
+                         intersect_rectangle.height);
+    }
+  else
+    {
+      gdk_window_clear_area (clist->clist_window,
+                            cell_rectangle.x,
+                            cell_rectangle.y,
+                            cell_rectangle.width,
+                            cell_rectangle.height);
+
+      cell_rectangle.y += clist->row_height + CELL_SPACING;
+      gdk_window_clear_area (clist->clist_window,
+                            cell_rectangle.x,
+                            cell_rectangle.y,
+                            cell_rectangle.width,
+                            cell_rectangle.height);
+      
+      gdk_draw_rectangle (clist->clist_window,
+                         bg_gc,
+                         TRUE,
+                         row_rectangle.x,
+                         row_rectangle.y,
+                         row_rectangle.width,
+                         row_rectangle.height);
+    }
+
+
+  /* iterate and draw all the columns (row cells) and draw their contents */
+  for (i = 0; i < clist->columns; i++)
+    {
+      clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
+      clip_rectangle.width = clist->column[i].area.width;
+
+      /* calculate clipping region clipping region */
+      if (!area)
+       {
+         rect = &clip_rectangle;
+       }
+      else
+       {
+         if (!gdk_rectangle_intersect (area, &clip_rectangle, &intersect_rectangle))
+           continue;
+         rect = &intersect_rectangle;
+       }
+
+      /* calculate real width for column justification */
+      switch (clist_row->cell[i].type)
+       {
+       case GTK_CELL_EMPTY:
+         continue;
+         break;
+
+       case GTK_CELL_TEXT:
+         width = gdk_string_width (GTK_WIDGET (clist)->style->font,
+                                   GTK_CELL_TEXT (clist_row->cell[i])->text);
+         break;
+
+       case GTK_CELL_PIXMAP:
+         gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
+         pixmap_width = width;
+         break;
+
+       case GTK_CELL_PIXTEXT:
+         gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
+         pixmap_width = width;
+         width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
+         width = gdk_string_width (GTK_WIDGET (clist)->style->font,
+                                   GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
+         break;
+
+       case GTK_CELL_WIDGET:
+         /* unimplimented */
+         continue;
+         break;
+
+       default:
+         continue;
+         break;
+       }
+
+      switch (clist->column[i].justification)
+       {
+       case GTK_JUSTIFY_LEFT:
+         offset = clip_rectangle.x;
+         break;
+
+       case GTK_JUSTIFY_RIGHT:
+         offset = (clip_rectangle.x + clip_rectangle.width) - width;
+         break;
+
+       case GTK_JUSTIFY_CENTER:
+         offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
+         break;
+
+       case GTK_JUSTIFY_FILL:
+         offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
+         break;
+
+       default:
+         offset = 0;
+         break;
+       };
+
+      /*
+       * Draw Text or Pixmap
+       */
+      switch (clist_row->cell[i].type)
+       {
+       case GTK_CELL_EMPTY:
+         continue;
+         break;
+
+       case GTK_CELL_TEXT:
+         gdk_gc_set_clip_rectangle (fg_gc, rect);
+
+         gdk_draw_string (clist->clist_window, 
+                          widget->style->font,
+                          fg_gc,
+                          offset + clist_row->cell[i].horizontal,
+                          row_rectangle.y + clist->row_center_offset + 
+                          clist_row->cell[i].verticle,
+                          GTK_CELL_TEXT (clist_row->cell[i])->text);
+
+         gdk_gc_set_clip_rectangle (fg_gc, NULL);
+         break;
+
+       case GTK_CELL_PIXMAP:
+         xsrc = 0;
+         ysrc = 0;
+         xdest = offset + clist_row->cell[i].horizontal;
+         ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
+           clist_row->cell[i].verticle;
+
+         gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
+         gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
+
+         gdk_draw_pixmap (clist->clist_window,
+                          fg_gc,
+                          GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
+                          xsrc, ysrc,
+                          xdest,
+                          ydest,
+                          pixmap_width, height);
+
+         gdk_gc_set_clip_origin (fg_gc, 0, 0);
+         gdk_gc_set_clip_mask (fg_gc, NULL);
+         break;
+
+       case GTK_CELL_PIXTEXT:
+         /* draw the pixmap */
+         xsrc = 0;
+         ysrc = 0;
+         xdest = offset + clist_row->cell[i].horizontal;
+         ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
+           clist_row->cell[i].verticle;
+
+         gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
+         gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
+
+         gdk_draw_pixmap (clist->clist_window,
+                          fg_gc,
+                          GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
+                          xsrc, ysrc,
+                          xdest,
+                          ydest,
+                          pixmap_width, height);
+
+         gdk_gc_set_clip_origin (fg_gc, 0, 0);
+
+         offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
+         
+         /* draw the string */
+         gdk_gc_set_clip_rectangle (fg_gc, rect);
+
+         gdk_draw_string (clist->clist_window, 
+                          widget->style->font,
+                          fg_gc,
+                          offset + clist_row->cell[i].horizontal,
+                          row_rectangle.y + clist->row_center_offset + 
+                          clist_row->cell[i].verticle,
+                          GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
+
+         gdk_gc_set_clip_rectangle (fg_gc, NULL);
+
+         break;
+
+       case GTK_CELL_WIDGET:
+         /* unimplimented */
+         continue;
+         break;
+
+       default:
+         continue;
+         break;
+       }
+    }
+}
+
+static void
+gtk_clist_draw_rows (GtkCList * clist,
+                    GdkRectangle * area)
+{
+  GList *list;
+  GtkCListRow *clist_row;
+  int i, first_row, last_row;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (clist->row_height == 0)
+    return;
+
+  if (area)
+    {
+      first_row = ROW_FROM_YPIXEL (clist, area->y);
+      last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
+    }
+  else
+    {
+      first_row = ROW_FROM_YPIXEL (clist, 0);
+      last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
+    }
+
+  list = g_list_nth (clist->row_list, first_row);
+  i = first_row;
+  while (list)
+    {
+      clist_row = list->data;
+      list = list->next;
+
+      if (i > last_row)
+       return;
+
+      gtk_clist_draw_row (clist, area, i, clist_row);
+      i++;
+    }
+
+  if (!area)
+    gdk_window_clear_area (clist->clist_window,
+                          0, ROW_TOP_YPIXEL (clist, i + 1) - 1,
+                          -1, -1);
+}
+
+static gint
+gtk_clist_get_selection_info (GtkCList * clist,
+                             gint x,
+                             gint y,
+                             gint * row,
+                             gint * column)
+{
+  gint trow, tcol;
+
+  g_return_val_if_fail (clist != NULL, 0);
+
+  /* bounds checking, return false if the user clicked 
+   * on a blank area */
+  trow = ROW_FROM_YPIXEL (clist, y);
+  if (trow >= clist->rows)
+    return 0;
+
+  if (row)
+    *row = trow;
+
+  tcol = COLUMN_FROM_XPIXEL (clist, x);
+  if (tcol >= clist->columns)
+    return 0;
+
+  if (column)
+    *column = tcol;
+
+  return 1;
+}
+
+static void
+gtk_clist_real_select_row (GtkCList * clist,
+                          gint row,
+                          gint column,
+                          GdkEventButton * event)
+{
+  gint i;
+  GList *list;
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row >= clist->rows)
+    return;
+
+  switch (clist->selection_mode)
+    {
+    case GTK_SELECTION_SINGLE:
+      i = 0;
+      list = clist->row_list;
+      while (list)
+       {
+         clist_row = list->data;
+         list = list->next;
+
+         if (row == i)
+           {
+             if (clist_row->state == GTK_STATE_SELECTED)
+               {
+                 clist_row->state = GTK_STATE_NORMAL;
+                 gtk_clist_unselect_row (clist, i, column);
+               }
+             else
+               {
+                 clist_row->state = GTK_STATE_SELECTED;
+               }
+
+             if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
+               gtk_clist_draw_row (clist, NULL, row, clist_row);
+           }
+         else if (clist_row->state == GTK_STATE_SELECTED)
+           {
+             gtk_clist_unselect_row (clist, i, column);
+           }
+
+         i++;
+       }
+      break;
+
+    case GTK_SELECTION_BROWSE:
+      i = 0;
+      list = clist->row_list;
+      while (list)
+       {
+         clist_row = list->data;
+         list = list->next;
+
+         if (row == i)
+           {
+             clist_row->state = GTK_STATE_SELECTED;
+
+             if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
+               gtk_clist_draw_row (clist, NULL, row, clist_row);
+           }
+         else if (clist_row->state == GTK_STATE_SELECTED)
+           {
+             gtk_clist_unselect_row (clist, i, column);
+           }
+
+         i++;
+       }
+      break;
+
+    case GTK_SELECTION_MULTIPLE:
+      i = 0;
+      list = clist->row_list;
+      while (list)
+       {
+         clist_row = list->data;
+         list = list->next;
+
+         if (row == i)
+           {
+             if (clist_row->state == GTK_STATE_SELECTED)
+               {
+                 clist_row->state = GTK_STATE_NORMAL;
+                 gtk_clist_unselect_row (clist, i, column);
+               }
+             else
+               {
+                 clist_row->state = GTK_STATE_SELECTED;
+               }
+
+             if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
+               gtk_clist_draw_row (clist, NULL, row, clist_row);
+           }
+
+         i++;
+       }
+      break;
+
+    case GTK_SELECTION_EXTENDED:
+      break;
+
+    default:
+      break;
+    }
+}
+
+static void
+gtk_clist_real_unselect_row (GtkCList * clist,
+                            gint row,
+                            gint column,
+                            GdkEventButton * event)
+{
+  GtkCListRow *clist_row;
+
+  g_return_if_fail (clist != NULL);
+
+  if (row < 0 || row > (clist->rows - 1))
+    return;
+
+  clist_row = (g_list_nth (clist->row_list, row))->data;
+  clist_row->state = GTK_STATE_NORMAL;
+
+  if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
+    gtk_clist_draw_row (clist, NULL, row, clist_row);
+}
+
+static void
+gtk_clist_draw (GtkWidget * widget,
+               GdkRectangle * area)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (area != NULL);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      clist = GTK_CLIST (widget);
+
+      gdk_window_clear_area (widget->window,
+                            area->x, area->y,
+                            area->width, area->height);
+
+      /* draw list shadow/border */
+      gtk_draw_shadow (widget->style, widget->window,
+                      GTK_STATE_NORMAL, clist->shadow_type,
+                      0, 0, -1, -1);
+
+      gdk_window_clear_area (clist->clist_window,
+                            0, 0, -1, -1);
+
+      gtk_clist_draw_rows (clist, NULL);
+    }
+}
+
+static gint
+gtk_clist_expose (GtkWidget * widget,
+                 GdkEventExpose * event)
+{
+  GtkCList *clist;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      clist = GTK_CLIST (widget);
+
+      /* draw border */
+      if (event->window == widget->window)
+       gtk_draw_shadow (widget->style, widget->window,
+                        GTK_STATE_NORMAL, clist->shadow_type,
+                        0, 0, -1, -1);
+
+      /* exposure events on the list */
+      if (event->window == clist->clist_window)
+       gtk_clist_draw_rows (clist, &event->area);
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_clist_button_press (GtkWidget * widget,
+                       GdkEventButton * event)
+{
+  GtkCList *clist;
+  gint x, y, row, column;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  clist = GTK_CLIST (widget);
+
+  /* selections on the list */
+  if (event->window == clist->clist_window)
+    {
+      x = event->x;
+      y = event->y;
+
+      if (gtk_clist_get_selection_info (clist, x, y, &row, &column))
+       gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                        row, column, event);
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_clist_size_request (GtkWidget * widget,
+                       GtkRequisition * requisition)
+{
+  gint i;
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (requisition != NULL);
+
+  clist = GTK_CLIST (widget);
+
+  requisition->width = 0;
+  requisition->height = 0;
+
+  /* compute the size of the column title (title) area */
+  clist->column_title_area.height = 0;
+  for (i = 0; i < clist->columns; i++)
+    {
+      gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
+      clist->column_title_area.height = MAX (clist->column_title_area.height,
+                                            clist->column[i].button->requisition.height);
+    }
+  requisition->height += clist->column_title_area.height;
+
+  /* add the vscrollbar space */
+  if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
+      GTK_WIDGET_VISIBLE (clist->vscrollbar))
+    {
+      gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
+
+      requisition->width += clist->vscrollbar->requisition.width;
+      requisition->height = MAX (requisition->height,
+                                clist->vscrollbar->requisition.height);
+    }
+
+  /* add the hscrollbar space */
+  if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
+      GTK_WIDGET_VISIBLE (clist->hscrollbar))
+    {
+      gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
+
+      requisition->height += clist->hscrollbar->requisition.height;
+      requisition->width = MAX (clist->hscrollbar->requisition.width, 
+                               requisition->width - 
+                               clist->vscrollbar->requisition.width);
+
+    }
+
+  requisition->width += widget->style->klass->xthickness * 2 +
+    GTK_CONTAINER (widget)->border_width * 2;
+  requisition->height += widget->style->klass->ythickness * 2 +
+    GTK_CONTAINER (widget)->border_width * 2;
+}
+
+static void
+gtk_clist_size_allocate (GtkWidget * widget,
+                        GtkAllocation * allocation)
+{
+  GtkCList *clist;
+  GtkAllocation clist_allocation;
+  GtkAllocation child_allocation;
+  gint i, vscrollbar_vis, hscrollbar_vis;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (allocation != NULL);
+
+  clist = GTK_CLIST (widget);
+  widget->allocation = *allocation;
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_move_resize (widget->window,
+                             allocation->x + GTK_CONTAINER (widget)->border_width,
+                             allocation->y + GTK_CONTAINER (widget)->border_width,
+                             allocation->width - GTK_CONTAINER (widget)->border_width * 2,
+                             allocation->height - GTK_CONTAINER (widget)->border_width * 2);
+
+      /*
+       * calculate internal size of the clist, compensating if
+       * there is no border
+       */
+      if (clist->shadow_type == GTK_SHADOW_NONE)
+       {
+         clist->internal_allocation.x = 0;
+         clist->internal_allocation.y = 0;
+         clist->internal_allocation.width = allocation->width -
+           GTK_CONTAINER (widget)->border_width * 2;
+         clist->internal_allocation.height = allocation->height -
+           GTK_CONTAINER (widget)->border_width * 2;
+       }
+      else
+       {
+         clist->internal_allocation.x = widget->style->klass->xthickness;
+         clist->internal_allocation.y = widget->style->klass->ythickness;
+         clist->internal_allocation.width = allocation->width -
+           GTK_CONTAINER (widget)->border_width * 2 -
+           widget->style->klass->xthickness * 2;
+         clist->internal_allocation.height = allocation->height -
+           GTK_CONTAINER (widget)->border_width * 2 -
+           widget->style->klass->ythickness * 2;
+       }
+
+      /*
+       * get the clist cell window allocated correctly
+       */
+      clist_allocation.x = clist->internal_allocation.x;
+      clist_allocation.y = clist->internal_allocation.y +
+       clist->column_title_area.height;
+      clist_allocation.width = clist->internal_allocation.width;
+      clist_allocation.height = clist->internal_allocation.height -
+       clist->column_title_area.height;
+
+      /* 
+       * here's where we decide to show/not show the scrollbars
+       */
+      vscrollbar_vis = 0;
+      hscrollbar_vis = 0;
+
+      for (i = 0; i <= 1; i++)
+       {
+         if (LIST_HEIGHT (clist) <= clist_allocation.height &&
+             clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
+           {
+             vscrollbar_vis = 0;
+           }
+         else
+           {
+             if (!vscrollbar_vis)
+               {
+                 vscrollbar_vis = 1;
+                 clist_allocation.width -= clist->vscrollbar->requisition.width;
+               }  
+           }
+         
+         if (LIST_WIDTH (clist) <= clist_allocation.width &&
+             clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
+           {
+             hscrollbar_vis = 0;
+           }
+         else
+           {
+             if (!hscrollbar_vis)
+               {
+                 hscrollbar_vis = 1;
+                 clist_allocation.height -= clist->hscrollbar->requisition.height;     
+               }  
+           }
+       }
+
+      clist->clist_window_width = clist_allocation.width;
+      clist->clist_window_height = clist_allocation.height;
+
+      gdk_window_move_resize (clist->clist_window,
+                             clist_allocation.x,
+                             clist_allocation.y,
+                             clist_allocation.width,
+                             clist_allocation.height);
+
+
+      /*
+       * position the window which holds the column title buttons
+       */
+      clist->column_title_area.x = 0;
+      clist->column_title_area.y = 0;
+      clist->column_title_area.width = clist->internal_allocation.width -
+       (vscrollbar_vis ? clist->vscrollbar->requisition.width : 0);
+
+      gdk_window_move_resize (clist->title_window,
+                             clist->internal_allocation.x,
+                             clist->internal_allocation.y,
+                             clist->column_title_area.width,
+                             clist->column_title_area.height);
+
+      /*
+       * column button allocation
+       */
+      gtk_clist_size_allocate_title_buttons (clist);
+      gtk_clist_size_allocate_columns (clist);
+
+      /*
+       * allocate the vscrollbar
+       */
+      if (vscrollbar_vis)
+       {
+         if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
+           gtk_widget_show (clist->vscrollbar);
+             
+         child_allocation.x = clist->internal_allocation.x + 
+           clist->internal_allocation.width -
+           clist->vscrollbar->requisition.width;
+         child_allocation.y = clist->internal_allocation.y;
+         child_allocation.width = clist->vscrollbar->requisition.width;
+         child_allocation.height = clist->internal_allocation.height -
+           (hscrollbar_vis ? clist->hscrollbar->requisition.height : 0);
+
+         gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
+       }
+      else
+       {
+          if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
+               gtk_widget_hide (clist->vscrollbar);
+       }
+
+      if (hscrollbar_vis)
+       {
+         if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
+           gtk_widget_show (clist->hscrollbar);
+      
+         child_allocation.x = clist->internal_allocation.x;
+         child_allocation.y = clist->internal_allocation.y +
+           clist->internal_allocation.height -
+           clist->hscrollbar->requisition.height;
+         child_allocation.width = clist->internal_allocation.width - 
+           (vscrollbar_vis ? clist->vscrollbar->requisition.width : 0);
+         child_allocation.height = clist->hscrollbar->requisition.height;
+
+         gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
+       }
+      else
+       {
+         if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
+               gtk_widget_hide (clist->hscrollbar);
+       }
+    }
+
+  /*
+   * set the vscrollbar adjustments
+   */
+  gtk_clist_adjust_scrollbars (clist);
+}
+
+static void
+gtk_clist_size_allocate_title_buttons (GtkCList * clist)
+{
+  gint i;
+  GtkAllocation button_allocation;
+
+  button_allocation.x = clist->hoffset;
+  button_allocation.y = 0;
+  button_allocation.height = clist->column_title_area.height;
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      button_allocation.width = clist->column[i].width;
+
+      if (i == clist->columns - 1)
+       {
+         button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
+
+         if (button_allocation.width < (clist->column_title_area.width - button_allocation.x))
+           button_allocation.width = clist->column_title_area.width - button_allocation.x;
+       }
+      else
+       {
+         button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
+       }
+
+      gtk_widget_size_allocate (clist->column[i].button, &button_allocation);
+      button_allocation.x += button_allocation.width;
+    }
+}
+
+static void
+gtk_clist_size_allocate_columns (GtkCList * clist)
+{
+  gint i, xoffset;
+
+  xoffset = 0;
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
+
+      if (i == clist->columns - 1)
+       {
+         clist->column[i].area.width = MAX (clist->column[i].width,
+                                            clist->column_title_area.width -
+                                            xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
+       }
+      else
+       {
+         clist->column[i].area.width = clist->column[i].width;
+       }
+
+      xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
+    }
+}
+
+static void
+gtk_clist_foreach (GtkContainer * container,
+                  GtkCallback callback,
+                  gpointer callback_data)
+{
+  gint i;
+  GtkCList *clist;
+
+  g_return_if_fail (container != NULL);
+  g_return_if_fail (GTK_IS_CLIST (container));
+  g_return_if_fail (callback != NULL);
+
+  clist = GTK_CLIST (container);
+
+  /* callback for the column buttons */
+  for (i = 0; i < clist->columns; i++)
+    (*callback) (clist->column[i].button, callback_data);
+
+  /* callbacks for the scrollbars */
+  (*callback) (clist->vscrollbar, callback_data);
+  (*callback) (clist->hscrollbar, callback_data);
+}
+
+/* BUTTONS */
+static void
+gtk_clist_column_button_realize (GtkWidget * widget,
+                                gpointer data)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (data));
+
+  clist = GTK_CLIST (data);
+
+  if (widget->window && clist->title_window)
+    gdk_window_reparent (widget->window, clist->title_window,
+                        widget->allocation.x, 0);
+}
+
+static void
+gtk_clist_column_button_clicked (GtkWidget * widget,
+                                gpointer data)
+{
+  gint i;
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (data));
+
+  clist = GTK_CLIST (data);
+
+  /* find the column who's button was pressed */
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].button == widget)
+      break;
+
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
+}
+
+/*
+ * SCROLLBARS
+ *
+ * functions:
+ *   gtk_clist_adjust_scrollbars
+ *   gtk_clist_vadjustment_changed
+ *   gtk_clist_hadjustment_changed
+ *   gtk_clist_vadjustment_value_changed
+ *   gtk_clist_hadjustment_value_changed
+ */
+static void
+gtk_clist_adjust_scrollbars (GtkCList * clist)
+{
+  GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
+  GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
+  GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
+  GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
+  GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
+
+  if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
+    {
+      GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - 
+       clist->clist_window_height;
+      gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
+                              "value_changed");
+    }
+
+  GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
+  GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
+  GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
+  GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
+  GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
+
+  if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
+    {
+      GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - 
+       clist->clist_window_width;
+      gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
+                              "value_changed");
+    }
+
+  if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
+      clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
+    {
+      if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
+       {
+         gtk_widget_hide (clist->vscrollbar);
+         gtk_widget_queue_resize (GTK_WIDGET (clist));
+       }
+    }
+  else
+    {
+      if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
+       {
+         gtk_widget_show (clist->vscrollbar);
+         gtk_widget_queue_resize (GTK_WIDGET (clist));
+       }
+    }
+
+  if (LIST_WIDTH (clist) <= clist->clist_window_width &&
+      clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
+    {
+      if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
+       {
+         gtk_widget_hide (clist->hscrollbar);
+         gtk_widget_queue_resize (GTK_WIDGET (clist));
+       }
+    }
+  else
+    {
+      if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
+       {
+         gtk_widget_show (clist->hscrollbar);
+         gtk_widget_queue_resize (GTK_WIDGET (clist));
+       }
+    }
+
+  gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
+  gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
+}
+
+static void
+gtk_clist_vadjustment_changed (GtkAdjustment * adjustment,
+                              gpointer data)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+
+  clist = GTK_CLIST (data);
+}
+
+static void
+gtk_clist_hadjustment_changed (GtkAdjustment * adjustment,
+                              gpointer data)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+
+  clist = GTK_CLIST (data);
+}
+
+static void
+gtk_clist_vadjustment_value_changed (GtkAdjustment * adjustment,
+                                    gpointer data)
+{
+  GtkCList *clist;
+  GdkRectangle area;
+  gint diff, value;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (GTK_IS_CLIST (data));
+
+  clist = GTK_CLIST (data);
+
+  value = adjustment->value;
+
+  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
+    {
+      if (value > -clist->voffset)
+       {
+         /* scroll down */
+         diff = value + clist->voffset;
+
+         /* we have to re-draw the whole screen here... */
+         if (diff >= clist->clist_window_height)
+           {
+             clist->voffset = -value;
+             gtk_clist_draw_rows (clist, NULL);
+             return;
+           }
+
+         gdk_window_copy_area (clist->clist_window,
+                               GTK_WIDGET (clist)->style->white_gc,
+                               0, 0,
+                               clist->clist_window,
+                               0,
+                               diff,
+                               clist->clist_window_width,
+                               clist->clist_window_height - diff);
+
+         area.x = 0;
+         area.y = clist->clist_window_height - diff;
+         area.width = clist->clist_window_width;
+         area.height = diff;
+       }
+      else
+       {
+         /* scroll up */
+         diff = -clist->voffset - value;
+
+         /* we have to re-draw the whole screen here... */
+         if (diff >= clist->clist_window_height)
+           {
+             clist->voffset = -value;
+             gtk_clist_draw_rows (clist, NULL);
+             return;
+           }
+
+         gdk_window_copy_area (clist->clist_window,
+                               GTK_WIDGET (clist)->style->white_gc,
+                               0, diff,
+                               clist->clist_window,
+                               0,
+                               0,
+                               clist->clist_window_width,
+                               clist->clist_window_height - diff);
+
+         area.x = 0;
+         area.y = 0;
+         area.width = clist->clist_window_width;
+         area.height = diff;
+
+       }
+
+      clist->voffset = -value;
+    }
+
+  gtk_clist_draw_rows (clist, &area);
+}
+
+static void
+gtk_clist_hadjustment_value_changed (GtkAdjustment * adjustment,
+                                    gpointer data)
+{
+  GtkCList *clist;
+  GdkRectangle area;
+  gint i, diff, value;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (GTK_IS_CLIST (data));
+
+  clist = GTK_CLIST (data);
+
+  value = adjustment->value;
+
+  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
+    {
+      for (i = 0; i < clist->columns; i++)
+       {
+         clist->column[i].button->allocation.x -= value + clist->hoffset;
+
+         if (clist->column[i].button->window)
+           gdk_window_move (clist->column[i].button->window,
+                            clist->column[i].button->allocation.x,
+                            clist->column[i].button->allocation.y);
+       }
+
+      if (value > -clist->hoffset)
+       {
+         /* scroll right */
+         diff = value + clist->hoffset;
+
+         /* we have to re-draw the whole screen here... */
+         if (diff >= clist->clist_window_width)
+           {
+             clist->hoffset = -value;
+             gtk_clist_draw_rows (clist, NULL);
+             return;
+           }
+
+         gdk_window_copy_area (clist->clist_window,
+                               GTK_WIDGET (clist)->style->white_gc,
+                               0, 0,
+                               clist->clist_window,
+                               diff,
+                               0,
+                               clist->clist_window_width - diff,
+                               clist->clist_window_height);
+
+         area.x = clist->clist_window_width - diff;
+         area.y = 0;
+         area.width = diff;
+         area.height = clist->clist_window_height;
+       }
+      else
+       {
+         /* scroll left */
+         diff = -clist->hoffset - value;
+
+         /* we have to re-draw the whole screen here... */
+         if (diff >= clist->clist_window_width)
+           {
+             clist->hoffset = -value;
+             gtk_clist_draw_rows (clist, NULL);
+             return;
+           }
+
+         gdk_window_copy_area (clist->clist_window,
+                               GTK_WIDGET (clist)->style->white_gc,
+                               diff, 0,
+                               clist->clist_window,
+                               0,
+                               0,
+                               clist->clist_window_width - diff,
+                               clist->clist_window_height);
+
+         area.x = 0;
+         area.y = 0;
+         area.width = diff;
+         area.height = clist->clist_window_height;
+       }
+
+      clist->hoffset = -value;
+    }
+
+  gtk_clist_draw_rows (clist, &area);
+}
+
+/*
+ * Memory Allocation/Distruction Routines for GtkCList stuctures
+ *
+ * functions:
+ *   gtk_clist_columns_new
+ *   gtk_clist_column_title_new
+ *   gtk_clist_columns_delete
+ *   gtk_clist_row_new
+ *   gtk_clist_row_delete
+ *   gtk_clist_cell_empty
+ *   gtk_clist_cell_set_text
+ *   gtk_clist_cell_set_pixmap
+ */
+static GtkCListColumn *
+gtk_clist_columns_new (GtkCList * clist)
+{
+  gint i;
+  GtkCListColumn *column;
+
+  column = g_new (GtkCListColumn, clist->columns);
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      column[i].area.x = 0;
+      column[i].area.y = 0;
+      column[i].area.width = 0;
+      column[i].area.height = 0;
+      column[i].title = NULL;
+      column[i].button = NULL;
+      column[i].width = 0;
+      column[i].justification = GTK_JUSTIFY_LEFT;
+    }
+
+  return column;
+}
+
+static void
+gtk_clist_column_title_new (GtkCList * clist,
+                           gint column,
+                           gchar * title)
+{
+  if (clist->column[column].title)
+    g_free (clist->column[column].title);
+
+  clist->column[column].title = g_strdup (title);
+}
+
+static void
+gtk_clist_columns_delete (GtkCList * clist)
+{
+  gint i;
+
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].title)
+      g_free (clist->column[i].title);
+      
+  g_free (clist->column);
+}
+
+static GtkCListRow *
+gtk_clist_row_new (GtkCList * clist)
+{
+  int i;
+  GtkCListRow *clist_row;
+
+  clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
+  clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      clist_row->cell[i].type = GTK_CELL_EMPTY;
+      clist_row->cell[i].verticle = 0;
+      clist_row->cell[i].horizontal = 0;
+    }
+
+  clist_row->foreground = GTK_WIDGET (clist)->style->fg[GTK_STATE_NORMAL];
+  clist_row->background = GTK_WIDGET (clist)->style->bg[GTK_STATE_PRELIGHT];
+  clist_row->state = GTK_STATE_NORMAL;
+  clist_row->data = NULL;
+
+  return clist_row;
+}
+
+static void
+gtk_clist_row_delete (GtkCList * clist,
+                     GtkCListRow * clist_row)
+{
+  gint i;
+
+  for (i = 0; i < clist->columns; i++)
+    gtk_clist_cell_empty (clist, clist_row, i);
+
+  g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
+  g_mem_chunk_free (clist->row_mem_chunk, clist_row);
+
+}
+
+static void
+gtk_clist_cell_empty (GtkCList * clist,
+                     GtkCListRow * clist_row,
+                     gint column)
+{
+  switch (clist_row->cell[column].type)
+    {
+    case GTK_CELL_EMPTY:
+      break;
+      
+    case GTK_CELL_TEXT:
+      g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
+      break;
+      
+    case GTK_CELL_PIXMAP:
+      gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
+      gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
+      break;
+      
+    case GTK_CELL_PIXTEXT:
+      g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
+      gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
+      gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
+      break;
+
+    case GTK_CELL_WIDGET:
+      /* unimplimented */
+      break;
+      
+    default:
+      break;
+    }
+
+  clist_row->cell[column].type = GTK_CELL_EMPTY;
+}
+
+static void
+gtk_clist_cell_set_text (GtkCList * clist,
+                        GtkCListRow * clist_row,
+                        gint column,
+                        gchar * text)
+{
+  gtk_clist_cell_empty (clist, clist_row, column);
+
+  if (text)
+    {
+      clist_row->cell[column].type = GTK_CELL_TEXT;
+      GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
+    }
+}
+
+static void
+gtk_clist_cell_set_pixmap (GtkCList * clist,
+                          GtkCListRow * clist_row,
+                          gint column,
+                          GdkPixmap * pixmap,
+                          GdkBitmap * mask)
+{
+  gtk_clist_cell_empty (clist, clist_row, column);
+
+  if (pixmap && mask)
+    {
+      clist_row->cell[column].type = GTK_CELL_PIXMAP;
+      GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
+      GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
+    }
+}
+
+static void
+gtk_clist_cell_set_pixtext (GtkCList * clist,
+                           GtkCListRow * clist_row,
+                           gint column,
+                           gchar * text,
+                           guint8 spacing,
+                           GdkPixmap * pixmap,
+                           GdkBitmap * mask)
+{
+  gtk_clist_cell_empty (clist, clist_row, column);
+
+  if (text && pixmap && mask)
+    {
+      clist_row->cell[column].type = GTK_CELL_PIXTEXT;
+      GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
+      GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
+      GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
+      GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
+    }
+}
diff --git a/gtk/gtkclist.h b/gtk/gtkclist.h
new file mode 100644 (file)
index 0000000..91ca04c
--- /dev/null
@@ -0,0 +1,405 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald
+ * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __GTK_CLIST_H__
+#define __GTK_CLIST_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkalignment.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkhscrollbar.h>
+#include <gtk/gtkvscrollbar.h>
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                         /* __cplusplus */
+
+/* clist flags */
+enum                    
+{
+  CLIST_FROZEN          = 1 << 0,                                     
+  CLIST_IN_DRAG         = 1 << 1,                                        
+  CLIST_ROW_HEIGHT_SET  = 1 << 2
+}; 
+
+/* cell types */
+typedef enum
+{
+  GTK_CELL_EMPTY,
+  GTK_CELL_TEXT,
+  GTK_CELL_PIXMAP,
+  GTK_CELL_PIXTEXT,
+  GTK_CELL_WIDGET
+} GtkCellType;
+
+#define GTK_CLIST(obj)          GTK_CHECK_CAST (obj, gtk_clist_get_type (), GtkCList)
+#define GTK_CLIST_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_clist_get_type (), GtkCListClass)
+#define GTK_IS_CLIST(obj)       GTK_CHECK_TYPE (obj, gtk_clist_get_type ())
+
+#define GTK_CLIST_FLAGS(clist)             (GTK_CLIST (clist)->flags)
+#define GTK_CLIST_SET_FLAGS(clist,flag)    (GTK_CLIST_FLAGS (clist) |= (flag))
+#define GTK_CLIST_UNSET_FLAGS(clist,flag)  (GTK_CLIST_FLAGS (clist) &= ~(flag))
+
+#define GTK_CLIST_FROZEN(clist)            (GTK_CLIST_FLAGS (clist) & CLIST_FROZEN)
+#define GTK_CLIST_IN_DRAG(clist)           (GTK_CLIST_FLAGS (clist) & CLIST_IN_DRAG)
+#define GTK_CLIST_ROW_HEIGHT_SET(clist)    (GTK_CLIST_FLAGS (clist) & CLIST_ROW_HEIGHT_SET)
+
+/* pointer casting for cells */
+#define GTK_CELL_TEXT(cell)     (((GtkCellText *) &(cell)))
+#define GTK_CELL_PIXMAP(cell)   (((GtkCellPixmap *) &(cell)))
+#define GTK_CELL_PIXTEXT(cell)  (((GtkCellPixText *) &(cell)))
+#define GTK_CELL_WIDGET(cell)   (((GtkCellWidget *) &(cell)))
+
+typedef struct _GtkCList GtkCList;
+typedef struct _GtkCListClass GtkCListClass;
+typedef struct _GtkCListColumn GtkCListColumn;
+typedef struct _GtkCListRow GtkCListRow;
+
+typedef struct _GtkCell GtkCell;
+typedef struct _GtkCellText GtkCellText;
+typedef struct _GtkCellPixmap GtkCellPixmap;
+typedef struct _GtkCellPixText GtkCellPixText;
+typedef struct _GtkCellWidget GtkCellWidget;
+
+struct _GtkCList
+{
+  GtkContainer container;
+  
+  guint8 flags;
+
+  /* allocation rectangle after the conatiner_border_width
+   * and the width of the shadow border */
+  GdkRectangle internal_allocation;
+  
+  /* memory chunks */
+  GMemChunk *row_mem_chunk;
+  GMemChunk *cell_mem_chunk;
+
+  /* rows */
+  gint rows;
+  gint row_center_offset;
+  gint row_height;
+  GList *row_list;
+  GList *row_list_end;
+  
+  /* columns */
+  gint columns;
+  GdkRectangle column_title_area;
+  GdkWindow *title_window;
+  
+  /* dynamicly allocated array of column structures */
+  GtkCListColumn *column;
+  
+  /*the scrolling window and it's height and width to
+   * make things a little speedier */
+  GdkWindow *clist_window;
+  gint clist_window_width;
+  gint clist_window_height;
+  
+  /* offsets for scrolling */
+  gint hoffset;
+  gint voffset;
+  
+  /* border shadow style */
+  GtkShadowType shadow_type;
+  
+  /* the list's selection mode (gtkenums.h) */
+  GtkSelectionMode selection_mode;
+
+  /* scrollbars */
+  GtkWidget *vscrollbar;
+  GtkWidget *hscrollbar;
+  guint8 vscrollbar_policy;
+  guint8 hscrollbar_policy;
+
+  /* xor GC for the verticle drag line */
+  GdkGC *xor_gc;
+
+  /* gc for drawing unselected cells */
+  GdkGC *fg_gc;
+  GdkGC *bg_gc;
+
+  /* cursor used to indicate dragging */
+  GdkCursor *cursor_drag;
+
+  /* the current x-pixel location of the xor-drag line */
+  gint x_drag;
+};
+
+struct _GtkCListClass
+{
+  GtkContainerClass parent_class;
+  
+  void (*select_row) (GtkCList * clist,
+                     gint row,
+                     gint column,
+                     GdkEventButton * event);
+  void (*unselect_row) (GtkCList * clist,
+                       gint row,
+                       gint column,
+                       GdkEventButton * event);
+  void (*click_column) (GtkCList * clist,
+                       gint column);
+};
+
+struct _GtkCListColumn
+{
+  gchar *title;
+  GdkRectangle area;
+  
+  GtkWidget *button;
+  gint width;
+  GtkJustification justification;
+};
+
+struct _GtkCListRow
+{
+  GtkCell *cell;
+  GtkStateType state;
+
+  GdkColor foreground;
+  GdkColor background;
+
+  gpointer data;
+};
+
+/* Cell Structures */
+struct _GtkCellText
+{
+  GtkCellType type;
+  
+  gint verticle;
+  gint horizontal;
+  
+  gchar *text;
+};
+
+struct _GtkCellPixmap
+{
+  GtkCellType type;
+  
+  gint verticle;
+  gint horizontal;
+  
+  GdkPixmap *pixmap;
+  GdkBitmap *mask;
+};
+
+struct _GtkCellPixText
+{
+  GtkCellType type;
+  
+  gint verticle;
+  gint horizontal;
+  
+  gchar *text;
+  guint8 spacing;
+  GdkPixmap *pixmap;
+  GdkBitmap *mask;
+};
+
+struct _GtkCellWidget
+{
+  GtkCellType type;
+  
+  gint verticle;
+  gint horizontal;
+  
+  GtkWidget *widget;
+};
+
+struct _GtkCell
+{
+  GtkCellType type;
+
+  gint verticle;
+  gint horizontal;
+
+  union {
+    gchar *text;
+
+    struct {
+      GdkPixmap *pixmap;
+      GdkBitmap *mask;
+    } pm;
+
+    struct {
+      gchar *text;
+      guint8 spacing;
+      GdkPixmap *pixmap;
+      GdkBitmap *mask;
+    } pt;
+
+    GtkWidget *widget;
+  } u;
+};
+
+guint gtk_clist_get_type (void);
+
+/* create a new GtkCList */
+GtkWidget *gtk_clist_new (int columns,
+                         gchar * titles[]);
+
+/* set the border style of the clist */
+void gtk_clist_set_border (GtkCList * clist,
+                          GtkShadowType border);
+
+/* set the clist's selection mode */
+void gtk_clist_set_selection_mode (GtkCList * clist,
+                                  GtkSelectionMode mode);
+
+/* set policy on the scrollbar, to either show them all the time
+ * or show them only when they are needed, ie., when there is more than one page
+ * of information */
+void gtk_clist_set_policy (GtkCList * clist,
+                          GtkPolicyType vscrollbar_policy,
+                          GtkPolicyType hscrollbar_policy);
+
+/* freeze all visual updates of the list, and then thaw the list after you have made
+ * a number of changes and the updates wil occure in a more efficent mannor than if
+ * you made them on a unfrozen list */
+void gtk_clist_freeze (GtkCList * clist);
+void gtk_clist_thaw (GtkCList * clist);
+
+/* set the title in the column title button */
+void gtk_clist_set_column_title (GtkCList * clist,
+                                gint column,
+                                gchar * title);
+
+/* set a widget instead of a title for the column title button */
+void gtk_clist_set_column_widget (GtkCList * clist,
+                                 gint column,
+                                 GtkWidget * widget);
+
+/* set the justification on a column */
+void gtk_clist_set_column_justification (GtkCList * clist,
+                                        gint column,
+                                        GtkJustification justification);
+
+/* set the pixel width of a column; this is a necessary step in
+ * creating a CList because otherwise the column width is chozen from
+ * the width of the column title, which will never be right */
+void gtk_clist_set_column_width (GtkCList * clist,
+                                gint column,
+                                gint width);
+
+/* change the height of the rows, the default is the hight of the current
+ * font */
+void gtk_clist_set_row_height (GtkCList * clist,
+                              gint height);
+
+/* scroll the viewing area of the list to the given column
+ * and row; row_align and col_align are between 0-1 representing the
+ * location the row should appear on the screnn, 0.0 being top or left,
+ * 1.0 being bottom or right */
+void gtk_clist_moveto (GtkCList * clist,
+                      gint row,
+                      gint column,
+                      gfloat row_align,
+                      gfloat col_align);
+
+/* sets a given cell's text, replacing it's current contents */
+void gtk_clist_set_text (GtkCList * clist,
+                        gint row,
+                        gint column,
+                        gchar * text);
+
+/* sets a given cell's pixmap, replacing it's current contents */
+void gtk_clist_set_pixmap (GtkCList * clist,
+                          gint row,
+                          gint column,
+                          GdkPixmap * pixmap,
+                          GdkBitmap * mask);
+
+/* sets a given cell's pixmap and text, replacing it's current contents */
+void gtk_clist_set_pixtext (GtkCList * clist,
+                           gint row,
+                           gint column,
+                           gchar * text,
+                           guint8 spacing,
+                           GdkPixmap * pixmap,
+                           GdkBitmap * mask);
+
+/* sets the foreground color of a row, the colar must already
+ * be allocated */
+void gtk_clist_set_foreground (GtkCList * clist,
+                              gint row,
+                              GdkColor * color);
+
+/* sets the background color of a row, the colar must already
+ * be allocated */
+void gtk_clist_set_background (GtkCList * clist,
+                              gint row,
+                              GdkColor * color);
+
+/* this sets a horizontal and verticle shift for drawing
+ * the contents of a cell; it can be positive or negitive; this is
+ * partuculary useful for indenting items in a column */
+void gtk_clist_set_shift (GtkCList * clist,
+                         gint row,
+                         gint column,
+                         gint verticle,
+                         gint horizontal);
+
+/* append returns the index of the row you just added, making
+ * it easier to append and modify a row */
+gint gtk_clist_append (GtkCList * clist,
+                      gchar * text[]);
+
+/* inserts a row at index row */
+void gtk_clist_insert (GtkCList * clist,
+                      gint row,
+                      gchar * text[]);
+
+/* removes row at index row */
+void gtk_clist_remove (GtkCList * clist,
+                      gint row);
+
+/* sets a arbitrary data pointer for a given row */
+void gtk_clist_set_row_data (GtkCList * clist,
+                            gint row,
+                            gpointer data);
+
+/* returns the data set for a row */
+gpointer gtk_clist_get_row_data (GtkCList * clist,
+                                gint row);
+
+/* force selection of a row */
+void gtk_clist_select_row (GtkCList * clist,
+                          gint row,
+                          gint column);
+
+/* force unselection of a row */
+void gtk_clist_unselect_row (GtkCList * clist,
+                            gint row,
+                            gint column);
+
+/* clear the entire list -- this is much faster than removing each item 
+ * with gtk_clist_remove */
+void gtk_clist_clear (GtkCList * clist);
+
+#ifdef __cplusplus
+}
+#endif                         /* __cplusplus */
+
+
+#endif                         /* __GTK_CLIST_H__ */
index b96b9b3d11ce51b00ec53dac4e900f044c85f18e..bfaa8ffb4cad55b7473d25bb43d13c14752ea83e 100644 (file)
@@ -1558,6 +1558,108 @@ create_list ()
     gtk_widget_destroy (window);
 }
 
+void
+create_clist ()
+{
+  gint i;
+  static GtkWidget *window = NULL;
+
+  static char *titles[] =
+  {
+    "Title 0",
+    "Title 1",
+    "Title 2",
+    "Title 3",
+    "Title 4",
+    "Title 5",
+    "Title 6"
+  };
+  static int columns = sizeof (titles) / sizeof (titles[0]);
+
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *clist;
+  GtkWidget *button;
+  GtkWidget *separator;
+
+
+  if (!window)
+    {
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+      gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                         GTK_SIGNAL_FUNC(destroy_window),
+                         &window);
+      gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                         GTK_SIGNAL_FUNC(destroy_window),
+                         &window);
+
+      gtk_window_set_title (GTK_WINDOW (window), "clist");
+      gtk_container_border_width (GTK_CONTAINER (window), 0);
+
+
+      box1 = gtk_vbox_new (FALSE, 0);
+      gtk_container_add (GTK_CONTAINER (window), box1);
+      gtk_widget_show (box1);
+
+
+      box2 = gtk_vbox_new (FALSE, 10);
+      gtk_container_border_width (GTK_CONTAINER (box2), 10);
+      gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+      gtk_widget_show (box2);
+
+
+      clist = gtk_clist_new (columns, titles);
+
+      gtk_clist_set_row_height (GTK_CLIST (clist), 20);
+      
+      for (i = 0; i < columns; i++)
+       gtk_clist_set_column_width (GTK_CLIST (clist), i, 50);
+
+      gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE);
+
+      gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+      gtk_clist_set_column_justification (GTK_CLIST (clist), 1, GTK_JUSTIFY_RIGHT);
+      gtk_clist_set_column_justification (GTK_CLIST (clist), 2, GTK_JUSTIFY_RIGHT);
+
+      for (i = 0; i < 100; i++)
+       gtk_clist_append (GTK_CLIST (clist), titles);
+
+
+      gtk_container_border_width (GTK_CONTAINER (clist), 5);
+      gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0);
+      gtk_widget_show (clist);
+
+
+      separator = gtk_hseparator_new ();
+      gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+      gtk_widget_show (separator);
+
+      box2 = gtk_vbox_new (FALSE, 10);
+      gtk_container_border_width (GTK_CONTAINER (box2), 10);
+      gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+      gtk_widget_show (box2);
+
+      button = gtk_button_new_with_label ("close");
+      gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                                GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                                GTK_OBJECT (window));
+
+      gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+      gtk_widget_grab_default (button);
+
+      gtk_widget_show (button);
+    }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+    gtk_widget_show (window);
+  else
+    gtk_widget_destroy (window);
+
+}
+
 void
 color_selection_ok (GtkWidget               *w,
                     GtkColorSelectionDialog *cs)
@@ -3529,6 +3631,7 @@ create_main_window ()
       { "drawing areas", NULL },
       { "entry", create_entry },
       { "list", create_list },
+      { "clist", create_clist},
       { "color selection", create_color_selection },
       { "file selection", create_file_selection },
       { "dialog", create_dialog },
index 81d8855f7ea7850a9bbc611a623fff5e1eaa51ae..1dc2304a33bf273eee7ea3faa4b09666cb5905a9 100644 (file)
@@ -28,8 +28,8 @@ style "scale"
 
 style "button"
 {
-  fg[PRELIGHT] = { 1.0, 1.0, 1.0 }
-  bg[PRELIGHT] = { 0, 0, 0.75 }
+#  fg[PRELIGHT] = { 1.0, 1.0, 1.0 }
+#  bg[PRELIGHT] = { 0, 0, 0.75 }
 }
 
 style "main_button" = "button"
@@ -61,7 +61,7 @@ style "curve"
   fg[NORMAL] = { 58000, 0, 0 }                 # red
 }
 
-widget_class "*" style "default"
+#widget_class "*" style "default"
 widget_class "GtkWindow" style "window"
 widget_class "GtkDialog" style "window"
 widget_class "GtkFileSelection" style "window"
index b96b9b3d11ce51b00ec53dac4e900f044c85f18e..bfaa8ffb4cad55b7473d25bb43d13c14752ea83e 100644 (file)
@@ -1558,6 +1558,108 @@ create_list ()
     gtk_widget_destroy (window);
 }
 
+void
+create_clist ()
+{
+  gint i;
+  static GtkWidget *window = NULL;
+
+  static char *titles[] =
+  {
+    "Title 0",
+    "Title 1",
+    "Title 2",
+    "Title 3",
+    "Title 4",
+    "Title 5",
+    "Title 6"
+  };
+  static int columns = sizeof (titles) / sizeof (titles[0]);
+
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *clist;
+  GtkWidget *button;
+  GtkWidget *separator;
+
+
+  if (!window)
+    {
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+      gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                         GTK_SIGNAL_FUNC(destroy_window),
+                         &window);
+      gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                         GTK_SIGNAL_FUNC(destroy_window),
+                         &window);
+
+      gtk_window_set_title (GTK_WINDOW (window), "clist");
+      gtk_container_border_width (GTK_CONTAINER (window), 0);
+
+
+      box1 = gtk_vbox_new (FALSE, 0);
+      gtk_container_add (GTK_CONTAINER (window), box1);
+      gtk_widget_show (box1);
+
+
+      box2 = gtk_vbox_new (FALSE, 10);
+      gtk_container_border_width (GTK_CONTAINER (box2), 10);
+      gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+      gtk_widget_show (box2);
+
+
+      clist = gtk_clist_new (columns, titles);
+
+      gtk_clist_set_row_height (GTK_CLIST (clist), 20);
+      
+      for (i = 0; i < columns; i++)
+       gtk_clist_set_column_width (GTK_CLIST (clist), i, 50);
+
+      gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE);
+
+      gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+      gtk_clist_set_column_justification (GTK_CLIST (clist), 1, GTK_JUSTIFY_RIGHT);
+      gtk_clist_set_column_justification (GTK_CLIST (clist), 2, GTK_JUSTIFY_RIGHT);
+
+      for (i = 0; i < 100; i++)
+       gtk_clist_append (GTK_CLIST (clist), titles);
+
+
+      gtk_container_border_width (GTK_CONTAINER (clist), 5);
+      gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0);
+      gtk_widget_show (clist);
+
+
+      separator = gtk_hseparator_new ();
+      gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+      gtk_widget_show (separator);
+
+      box2 = gtk_vbox_new (FALSE, 10);
+      gtk_container_border_width (GTK_CONTAINER (box2), 10);
+      gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+      gtk_widget_show (box2);
+
+      button = gtk_button_new_with_label ("close");
+      gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                                GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                                GTK_OBJECT (window));
+
+      gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+      gtk_widget_grab_default (button);
+
+      gtk_widget_show (button);
+    }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+    gtk_widget_show (window);
+  else
+    gtk_widget_destroy (window);
+
+}
+
 void
 color_selection_ok (GtkWidget               *w,
                     GtkColorSelectionDialog *cs)
@@ -3529,6 +3631,7 @@ create_main_window ()
       { "drawing areas", NULL },
       { "entry", create_entry },
       { "list", create_list },
+      { "clist", create_clist},
       { "color selection", create_color_selection },
       { "file selection", create_file_selection },
       { "dialog", create_dialog },
index 81d8855f7ea7850a9bbc611a623fff5e1eaa51ae..1dc2304a33bf273eee7ea3faa4b09666cb5905a9 100644 (file)
@@ -28,8 +28,8 @@ style "scale"
 
 style "button"
 {
-  fg[PRELIGHT] = { 1.0, 1.0, 1.0 }
-  bg[PRELIGHT] = { 0, 0, 0.75 }
+#  fg[PRELIGHT] = { 1.0, 1.0, 1.0 }
+#  bg[PRELIGHT] = { 0, 0, 0.75 }
 }
 
 style "main_button" = "button"
@@ -61,7 +61,7 @@ style "curve"
   fg[NORMAL] = { 58000, 0, 0 }                 # red
 }
 
-widget_class "*" style "default"
+#widget_class "*" style "default"
 widget_class "GtkWindow" style "window"
 widget_class "GtkDialog" style "window"
 widget_class "GtkFileSelection" style "window"