]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkclist.c
Merges from gtk-1-2
[~andy/gtk] / gtk / gtkclist.c
index ea1dc32033477f9207fc357bd7516f2143367841..34396b6295c06faefbe95dd69f4f175df58eec63 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
 #include <stdlib.h>
 #include <string.h>
-#include "../config.h"
+#include "config.h"
 #include "gtkmain.h"
 #include "gtkclist.h"
 #include "gtkbindings.h"
+#include "gtkdnd.h"
 #include <gdk/gdkkeysyms.h>
 
+/* length of button_actions array */
+#define MAX_BUTTON 5
+
 /* the number rows memchunk expands at a time */
-#define CLIST_OPTIMUM_SIZE 512
+#define CLIST_OPTIMUM_SIZE 64
 
 /* the width of the column resize windows */
 #define DRAG_WIDTH  6
@@ -43,9 +55,6 @@
 /* used for auto-scrolling */
 #define SCROLL_TIME  100
 
-/* scrollbar spacing class macro */
-#define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
-
 /* 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)) + \
@@ -71,13 +80,14 @@ COLUMN_FROM_XPIXEL (GtkCList * clist,
   gint i, cx;
 
   for (i = 0; i < clist->columns; i++)
-    {
-      cx = clist->column[i].area.x + clist->hoffset;
+    if (clist->column[i].visible)
+      {
+       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;
-    }
+       if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
+           x <= (cx + clist->column[i].area.width + COLUMN_INSET))
+         return i;
+      }
 
   /* no match */
   return -1;
@@ -112,15 +122,27 @@ LIST_WIDTH (GtkCList * clist)
   return 0;
 }
 
+/* returns the GList item for the nth row */
+#define        ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \
+                                (clist)->row_list_end : \
+                                g_list_nth ((clist)->row_list, (row)))
+
+
+#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (((GtkObject*) (_widget_))->klass)
 
-#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
+/* redraw the list if it's not frozen */
+#define CLIST_UNFROZEN(clist)     (((GtkCList*) (clist))->freeze_count == 0)
+#define        CLIST_REFRESH(clist)    G_STMT_START { \
+  if (CLIST_UNFROZEN (clist)) \
+    GTK_CLIST_CLASS_FW (clist)->refresh ((GtkCList*) (clist)); \
+} G_STMT_END
 
 
 /* Signals */
-enum
-{
+enum {
   SELECT_ROW,
   UNSELECT_ROW,
+  ROW_MOVE,
   CLICK_COLUMN,
   RESIZE_COLUMN,
   TOGGLE_FOCUS_ROW,
@@ -137,248 +159,308 @@ enum
   LAST_SIGNAL
 };
 
-enum
-{
+enum {
   SYNC_REMOVE,
   SYNC_INSERT
 };
 
-
-typedef void (*GtkCListSignal1) (GtkObject * object,
-                                gint arg1,
-                                gint arg2,
-                                GdkEvent * arg3,
-                                gpointer data);
-
-typedef void (*GtkCListSignal2) (GtkObject *object,
-                                gpointer data); 
-
-typedef void (*GtkCListSignal3) (GtkObject * object,
-                                gint arg1,
-                                gpointer data);
-typedef void (*GtkCListSignal4) (GtkObject * object,
-                                gint arg1,
-                                gfloat arg2,
-                                gpointer data);
-typedef void (*GtkCListSignal5) (GtkObject * object,
-                                gint arg1,
-                                gfloat arg2,
-                                gboolean arg3,
-                                gpointer data);
-
-
-static void sync_selection (GtkCList * clist,
-                           gint row,
-                            gint mode);
+enum {
+  ARG_0,
+  ARG_N_COLUMNS,
+  ARG_SHADOW_TYPE,
+  ARG_SELECTION_MODE,
+  ARG_ROW_HEIGHT,
+  ARG_TITLES_ACTIVE,
+  ARG_REORDERABLE,
+  ARG_USE_DRAG_ICONS,
+  ARG_SORT_TYPE
+};
 
 /* GtkCList Methods */
-static void gtk_clist_class_init (GtkCListClass * klass);
-static void gtk_clist_init (GtkCList * clist);
-static void real_clear (GtkCList * clist);
+static void gtk_clist_class_init (GtkCListClass *klass);
+static void gtk_clist_init       (GtkCList      *clist);
 
 /* GtkObject Methods */
-static void gtk_clist_destroy (GtkObject * object);
-static void gtk_clist_finalize (GtkObject * object);
-
+static void gtk_clist_destroy  (GtkObject *object);
+static void gtk_clist_finalize (GtkObject *object);
+static void gtk_clist_set_arg  (GtkObject *object,
+                               GtkArg    *arg,
+                               guint      arg_id);
+static void gtk_clist_get_arg  (GtkObject *object,
+                               GtkArg    *arg,
+                               guint      arg_id);
 
 /* 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 gint gtk_clist_button_release (GtkWidget * widget,
-                                     GdkEventButton * event);
-static gint gtk_clist_motion (GtkWidget * widget, 
-                             GdkEventMotion * event);
-static void gtk_clist_size_request (GtkWidget * widget,
-                                   GtkRequisition * requisition);
-static void gtk_clist_size_allocate (GtkWidget * widget,
-                                    GtkAllocation * allocation);
-static gint get_selection_info (GtkCList * clist,
-                               gint x,
-                               gint y,
-                               gint * row,
-                               gint * column);
+static void gtk_clist_set_scroll_adjustments (GtkCList      *clist,
+                                             GtkAdjustment *hadjustment,
+                                             GtkAdjustment *vadjustment);
+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_key_press       (GtkWidget        *widget,
+                                      GdkEventKey      *event);
+static gint gtk_clist_button_press    (GtkWidget        *widget,
+                                      GdkEventButton   *event);
+static gint gtk_clist_button_release  (GtkWidget        *widget,
+                                      GdkEventButton   *event);
+static gint gtk_clist_motion          (GtkWidget        *widget, 
+                                      GdkEventMotion   *event);
+static void gtk_clist_size_request    (GtkWidget        *widget,
+                                      GtkRequisition   *requisition);
+static void gtk_clist_size_allocate   (GtkWidget        *widget,
+                                      GtkAllocation    *allocation);
+static void gtk_clist_draw_focus      (GtkWidget        *widget);
+static gint gtk_clist_focus_in        (GtkWidget        *widget,
+                                      GdkEventFocus    *event);
+static gint gtk_clist_focus_out       (GtkWidget        *widget,
+                                      GdkEventFocus    *event);
+static gint gtk_clist_focus           (GtkContainer     *container,
+                                      GtkDirectionType  direction);
+static void gtk_clist_style_set       (GtkWidget        *widget,
+                                      GtkStyle         *previous_style);
+static void gtk_clist_drag_begin      (GtkWidget        *widget,
+                                      GdkDragContext   *context);
+static gint gtk_clist_drag_motion     (GtkWidget        *widget,
+                                      GdkDragContext   *context,
+                                      gint              x,
+                                      gint              y,
+                                      guint             time);
+static void gtk_clist_drag_leave      (GtkWidget        *widget,
+                                      GdkDragContext   *context,
+                                      guint             time);
+static void gtk_clist_drag_end        (GtkWidget        *widget,
+                                      GdkDragContext   *context);
+static gboolean gtk_clist_drag_drop   (GtkWidget      *widget,
+                                      GdkDragContext *context,
+                                      gint            x,
+                                      gint            y,
+                                      guint           time);
+static void gtk_clist_drag_data_get   (GtkWidget        *widget,
+                                      GdkDragContext   *context,
+                                      GtkSelectionData *selection_data,
+                                      guint             info,
+                                      guint             time);
+static void gtk_clist_drag_data_received (GtkWidget        *widget,
+                                         GdkDragContext   *context,
+                                         gint              x,
+                                         gint              y,
+                                         GtkSelectionData *selection_data,
+                                         guint             info,
+                                         guint             time);
 
 /* GtkContainer Methods */
-static void gtk_clist_forall (GtkContainer *container,
-                             gboolean      include_internals,
-                             GtkCallback   callback,
-                             gpointer      callback_data);
-
-/* Drawing */
-static void draw_row (GtkCList * clist,
-                     GdkRectangle * area,
-                     gint row,
-                     GtkCListRow * clist_row);
-static void draw_rows (GtkCList * clist,
-                      GdkRectangle * area);
-
-/* Size Allocation */
-static void size_allocate_title_buttons (GtkCList * clist);
-static void size_allocate_columns (GtkCList * clist);
+static void gtk_clist_set_focus_child (GtkContainer  *container,
+                                      GtkWidget     *child);
+static void gtk_clist_forall          (GtkContainer  *container,
+                                      gboolean       include_internals,
+                                      GtkCallback    callback,
+                                      gpointer       callback_data);
 
 /* Selection */
-static void toggle_row (GtkCList * clist,
-                       gint row,
-                       gint column,
-                       GdkEvent * event);
-static void select_row (GtkCList * clist,
-                       gint row,
-                       gint column,
-                       GdkEvent * event);
-static void unselect_row (GtkCList * clist,
-                         gint row,
-                         gint column,
-                         GdkEvent * event);
-static void real_select_row (GtkCList * clist,
-                            gint row,
-                            gint column,
-                            GdkEvent * event);
-static void real_unselect_row (GtkCList * clist,
-                              gint row,
-                              gint column,
-                              GdkEvent * event);
-static void update_extended_selection (GtkCList *clist,
-                                      gint row);
-static GList * selection_find (GtkCList *clist,
-                              gint row_number,
-                              GList *row_list_element);
-static void real_select_all (GtkCList * clist);
-static void real_unselect_all (GtkCList * clist);
-static void move_vertical (GtkCList *clist,
-                          gint row,
-                          gfloat align);
-static void move_horizontal (GtkCList *clist,
-                            gint diff);
-static void real_undo_selection (GtkCList * clist);
-static void fake_unselect_all (GtkCList *clist,
-                              gint row);
-static void fake_toggle_row (GtkCList *clist,
-                            gint row);
-static void resync_selection (GtkCList *clist,
-                             GdkEvent *event);
+static void toggle_row                (GtkCList      *clist,
+                                      gint           row,
+                                      gint           column,
+                                      GdkEvent      *event);
+static void real_select_row           (GtkCList      *clist,
+                                      gint           row,
+                                      gint           column,
+                                      GdkEvent      *event);
+static void real_unselect_row         (GtkCList      *clist,
+                                      gint           row,
+                                      gint           column,
+                                      GdkEvent      *event);
+static void update_extended_selection (GtkCList      *clist,
+                                      gint           row);
+static GList *selection_find          (GtkCList      *clist,
+                                      gint           row_number,
+                                      GList         *row_list_element);
+static void real_select_all           (GtkCList      *clist);
+static void real_unselect_all         (GtkCList      *clist);
+static void move_vertical             (GtkCList      *clist,
+                                      gint           row,
+                                      gfloat         align);
+static void move_horizontal           (GtkCList      *clist,
+                                      gint           diff);
+static void real_undo_selection       (GtkCList      *clist);
+static void fake_unselect_all         (GtkCList      *clist,
+                                      gint           row);
+static void fake_toggle_row           (GtkCList      *clist,
+                                      gint           row);
+static void resync_selection          (GtkCList      *clist,
+                                      GdkEvent      *event);
+static void sync_selection            (GtkCList      *clist,
+                                      gint           row,
+                                       gint           mode);
+static void set_anchor                (GtkCList      *clist,
+                                      gboolean       add_mode,
+                                      gint           anchor,
+                                      gint           undo_anchor);
+static void start_selection           (GtkCList      *clist);
+static void end_selection             (GtkCList      *clist);
+static void toggle_add_mode           (GtkCList      *clist);
+static void toggle_focus_row          (GtkCList      *clist);
+static void extend_selection          (GtkCList      *clist,
+                                      GtkScrollType  scroll_type,
+                                      gfloat         position,
+                                      gboolean       auto_start_selection);
+static gint get_selection_info        (GtkCList       *clist,
+                                      gint            x,
+                                      gint            y,
+                                      gint           *row,
+                                      gint           *column);
+
+/* Scrolling */
+static void move_focus_row     (GtkCList      *clist,
+                               GtkScrollType  scroll_type,
+                               gfloat         position);
+static void scroll_horizontal  (GtkCList      *clist,
+                               GtkScrollType  scroll_type,
+                               gfloat         position);
+static void scroll_vertical    (GtkCList      *clist,
+                               GtkScrollType  scroll_type,
+                               gfloat         position);
+static void move_horizontal    (GtkCList      *clist,
+                               gint           diff);
+static void move_vertical      (GtkCList      *clist,
+                               gint           row,
+                               gfloat         align);
+static gint horizontal_timeout (GtkCList      *clist);
+static gint vertical_timeout   (GtkCList      *clist);
+static void remove_grab        (GtkCList      *clist);
+
 
 /* Resize Columns */
-static void draw_xor_line (GtkCList * clist);
-static gint new_column_width (GtkCList * clist,
-                             gint column,
-                             gint * x);
-static void real_resize_column (GtkCList * clist,
-                               gint column,
-                               gint width);
-static void resize_column (GtkCList * clist,
-                          gint column,
-                          gint width);
-static void abort_column_resize (GtkCList *clist);
+static void draw_xor_line             (GtkCList       *clist);
+static gint new_column_width          (GtkCList       *clist,
+                                      gint            column,
+                                      gint           *x);
+static void column_auto_resize        (GtkCList       *clist,
+                                      GtkCListRow    *clist_row,
+                                      gint            column,
+                                      gint            old_width);
+static void real_resize_column        (GtkCList       *clist,
+                                      gint            column,
+                                      gint            width);
+static void abort_column_resize       (GtkCList       *clist);
+static void cell_size_request         (GtkCList       *clist,
+                                      GtkCListRow    *clist_row,
+                                      gint            column,
+                                      GtkRequisition *requisition);
 
 /* Buttons */
-static void column_button_create (GtkCList * clist,
-                                 gint column);
-static void column_button_clicked (GtkWidget * widget,
-                                  gpointer data);
-
-/* Scrollbars */
-static void create_scrollbars (GtkCList * clist);
-static void adjust_scrollbars (GtkCList * clist);
-static void check_exposures   (GtkCList * clist);
-static void vadjustment_changed (GtkAdjustment * adjustment,
-                                gpointer data);
-static void vadjustment_value_changed (GtkAdjustment * adjustment,
-                                      gpointer data);
-static void hadjustment_changed (GtkAdjustment * adjustment,
-                                gpointer data);
-static void hadjustment_value_changed (GtkAdjustment * adjustment,
-                                      gpointer data);
+static void column_button_create      (GtkCList       *clist,
+                                      gint            column);
+static void column_button_clicked     (GtkWidget      *widget,
+                                      gpointer        data);
+
+/* Adjustments */
+static void adjust_adjustments        (GtkCList       *clist,
+                                      gboolean        block_resize);
+static void check_exposures           (GtkCList       *clist);
+static void vadjustment_changed       (GtkAdjustment  *adjustment,
+                                      gpointer        data);
+static void vadjustment_value_changed (GtkAdjustment  *adjustment,
+                                      gpointer        data);
+static void hadjustment_changed       (GtkAdjustment  *adjustment,
+                                      gpointer        data);
+static void hadjustment_value_changed (GtkAdjustment  *adjustment,
+                                      gpointer        data);
+
+/* Drawing */
+static void get_cell_style   (GtkCList      *clist,
+                             GtkCListRow   *clist_row,
+                             gint           state,
+                             gint           column,
+                             GtkStyle     **style,
+                             GdkGC        **fg_gc,
+                             GdkGC        **bg_gc);
+static gint draw_cell_pixmap (GdkWindow     *window,
+                             GdkRectangle  *clip_rectangle,
+                             GdkGC         *fg_gc,
+                             GdkPixmap     *pixmap,
+                             GdkBitmap     *mask,
+                             gint           x,
+                             gint           y,
+                             gint           width,
+                             gint           height);
+static void draw_row         (GtkCList      *clist,
+                             GdkRectangle  *area,
+                             gint           row,
+                             GtkCListRow   *clist_row);
+static void draw_rows        (GtkCList      *clist,
+                             GdkRectangle  *area);
+static void clist_refresh    (GtkCList      *clist);
+static void draw_drag_highlight (GtkCList        *clist,
+                                GtkCListRow     *dest_row,
+                                gint             dest_row_number,
+                                GtkCListDragPos  drag_pos);
+     
+/* Size Allocation / Requisition */
+static void size_allocate_title_buttons (GtkCList *clist);
+static void size_allocate_columns       (GtkCList *clist,
+                                        gboolean  block_resize);
+static gint list_requisition_width      (GtkCList *clist);
 
 /* Memory Allocation/Distruction Routines */
-static GtkCListColumn *columns_new (GtkCList * clist);
-
-static void column_title_new (GtkCList    *clist,
-                             gint         column,
-                             const gchar *title);
-static void columns_delete (GtkCList * clist);
-
-static GtkCListRow *row_new (GtkCList * clist);
-
-static void row_delete (GtkCList * clist,
-                       GtkCListRow * clist_row);
-static void set_cell_contents (GtkCList    *clist,
-                              GtkCListRow *clist_row,
-                              gint         column,
-                              GtkCellType  type,
-                              const gchar *text,
-                              guint8       spacing,
-                              GdkPixmap   *pixmap,
-                              GdkBitmap   *mask);
-static gint real_insert_row (GtkCList * clist,
-                            gint row,
-                            gchar * text[]);
-static void real_remove_row (GtkCList * clist,
-                            gint row);
-
-/* Focus handling */
-static void gtk_clist_draw_focus (GtkWidget *widget);
-static gint gtk_clist_focus_in   (GtkWidget     *widget,
-                                 GdkEventFocus *event);
-static gint gtk_clist_focus_out  (GtkWidget     *widget,
-                                 GdkEventFocus *event);
-static gint gtk_clist_focus      (GtkContainer     *container,
-                                 GtkDirectionType  direction);
-static void gtk_clist_set_focus_child (GtkContainer *container,
-                                      GtkWidget    *child);
-static gint gtk_clist_key_press  (GtkWidget   *widget,
-                                 GdkEventKey *event);
-
-/* Selection handling */
-static void set_anchor (GtkCList *clist,
-                       gboolean  add_mode,
-                       gint      anchor,
-                       gint      undo_anchor);
-static void start_selection (GtkCList *clist);
-static void end_selection (GtkCList *clist);
-
-static void toggle_add_mode (GtkCList *clist);
-static void toggle_focus_row (GtkCList *clist);
-static void move_focus_row (GtkCList      *clist,
-                           GtkScrollType  scroll_type,
-                           gfloat         position);
-static void scroll_horizontal (GtkCList      *clist,
-                              GtkScrollType  scroll_type,
-                              gfloat         position);
-static void scroll_vertical (GtkCList      *clist,
-                            GtkScrollType  scroll_type,
-                            gfloat         position);
-static void extend_selection (GtkCList      *clist,
-                             GtkScrollType  scroll_type,
-                             gfloat         position,
-                             gboolean       auto_start_selection);
+static GtkCListColumn *columns_new (GtkCList      *clist);
+static void column_title_new       (GtkCList      *clist,
+                                   gint           column,
+                                   const gchar   *title);
+static void columns_delete         (GtkCList      *clist);
+static GtkCListRow *row_new        (GtkCList      *clist);
+static void row_delete             (GtkCList      *clist,
+                                   GtkCListRow   *clist_row);
+static void set_cell_contents      (GtkCList      *clist,
+                                   GtkCListRow   *clist_row,
+                                   gint           column,
+                                   GtkCellType    type,
+                                   const gchar   *text,
+                                   guint8         spacing,
+                                   GdkPixmap     *pixmap,
+                                   GdkBitmap     *mask);
+static gint real_insert_row        (GtkCList      *clist,
+                                   gint           row,
+                                   gchar         *text[]);
+static void real_remove_row        (GtkCList      *clist,
+                                   gint           row);
+static void real_clear             (GtkCList      *clist);
 
 /* Sorting */
-static gint default_compare (GtkCList     *clist,
-                            gconstpointer row1,
-                            gconstpointer row2);
-static GList * gtk_clist_merge (GtkCList *clist,
-                               GList    *a,
-                               GList    *b);
-static GList * gtk_clist_mergesort (GtkCList *clist,
-                                   GList    *list,
-                                   gint      num);
-static void real_sort_list (GtkCList *clist);
+static gint default_compare        (GtkCList      *clist,
+                                   gconstpointer  row1,
+                                   gconstpointer  row2);
+static void real_sort_list         (GtkCList      *clist);
+static GList *gtk_clist_merge      (GtkCList      *clist,
+                                   GList         *a,
+                                   GList         *b);
+static GList *gtk_clist_mergesort  (GtkCList      *clist,
+                                   GList         *list,
+                                   gint           num);
+/* Misc */
+static gboolean title_focus           (GtkCList  *clist,
+                                      gint       dir);
+static void real_row_move             (GtkCList  *clist,
+                                      gint       source_row,
+                                      gint       dest_row);
+static gint column_title_passive_func (GtkWidget *widget, 
+                                      GdkEvent  *event,
+                                      gpointer   data);
+static void drag_dest_cell            (GtkCList         *clist,
+                                      gint              x,
+                                      gint              y,
+                                      GtkCListDestInfo *dest_info);
 
-/* Fill in data after widget is realized and has style */
 
-static void add_style_data (GtkCList * clist);
 
 static GtkContainerClass *parent_class = NULL;
 static guint clist_signals[LAST_SIGNAL] = {0};
 
+static GtkTargetEntry clist_target_table = { "gtk-clist-drag-reorder", 0, 0};
 
 GtkType
 gtk_clist_get_type (void)
@@ -387,7 +469,7 @@ gtk_clist_get_type (void)
 
   if (!clist_type)
     {
-      GtkTypeInfo clist_info =
+      static const GtkTypeInfo clist_info =
       {
        "GtkCList",
        sizeof (GtkCList),
@@ -406,11 +488,12 @@ gtk_clist_get_type (void)
 }
 
 static void
-gtk_clist_class_init (GtkCListClass * klass)
+gtk_clist_class_init (GtkCListClass *klass)
 {
   GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkContainerClass *container_class;
+  GtkBindingSet *binding_set;
 
   object_class = (GtkObjectClass *) klass;
   widget_class = (GtkWidgetClass *) klass;
@@ -418,6 +501,52 @@ gtk_clist_class_init (GtkCListClass * klass)
 
   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
 
+  gtk_object_add_arg_type ("GtkCList::n_columns",
+                          GTK_TYPE_UINT,
+                          GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY,
+                          ARG_N_COLUMNS);
+  gtk_object_add_arg_type ("GtkCList::shadow_type",
+                          GTK_TYPE_SHADOW_TYPE,
+                          GTK_ARG_READWRITE,
+                          ARG_SHADOW_TYPE);
+  gtk_object_add_arg_type ("GtkCList::selection_mode",
+                          GTK_TYPE_SELECTION_MODE,
+                          GTK_ARG_READWRITE,
+                          ARG_SELECTION_MODE);
+  gtk_object_add_arg_type ("GtkCList::row_height",
+                          GTK_TYPE_UINT,
+                          GTK_ARG_READWRITE,
+                          ARG_ROW_HEIGHT);
+  gtk_object_add_arg_type ("GtkCList::reorderable",
+                          GTK_TYPE_BOOL,
+                          GTK_ARG_READWRITE,
+                          ARG_REORDERABLE);
+  gtk_object_add_arg_type ("GtkCList::titles_active",
+                          GTK_TYPE_BOOL,
+                          GTK_ARG_READWRITE,
+                          ARG_TITLES_ACTIVE);
+  gtk_object_add_arg_type ("GtkCList::use_drag_icons",
+                          GTK_TYPE_BOOL,
+                          GTK_ARG_READWRITE,
+                          ARG_USE_DRAG_ICONS);
+  gtk_object_add_arg_type ("GtkCList::sort_type",
+                          GTK_TYPE_SORT_TYPE,
+                          GTK_ARG_READWRITE,
+                          ARG_SORT_TYPE);  
+  object_class->set_arg = gtk_clist_set_arg;
+  object_class->get_arg = gtk_clist_get_arg;
+  object_class->destroy = gtk_clist_destroy;
+  object_class->finalize = gtk_clist_finalize;
+
+
+  widget_class->set_scroll_adjustments_signal =
+    gtk_signal_new ("set_scroll_adjustments",
+                   GTK_RUN_LAST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkCListClass, set_scroll_adjustments),
+                   gtk_marshal_NONE__POINTER_POINTER,
+                   GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
+
   clist_signals[SELECT_ROW] =
     gtk_signal_new ("select_row",
                    GTK_RUN_FIRST,
@@ -434,7 +563,15 @@ gtk_clist_class_init (GtkCListClass * klass)
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
                    gtk_marshal_NONE__INT_INT_POINTER,
-           GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
+                   GTK_TYPE_NONE, 3, GTK_TYPE_INT,
+                   GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
+  clist_signals[ROW_MOVE] =
+    gtk_signal_new ("row_move",
+                   GTK_RUN_LAST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkCListClass, row_move),
+                   gtk_marshal_NONE__INT_INT,
+                   GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
   clist_signals[CLICK_COLUMN] =
     gtk_signal_new ("click_column",
                    GTK_RUN_FIRST,
@@ -528,13 +665,8 @@ gtk_clist_class_init (GtkCListClass * klass)
                     GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
                     gtk_marshal_NONE__NONE,
                     GTK_TYPE_NONE, 0);
-
-
   gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
 
-  object_class->destroy = gtk_clist_destroy;
-  object_class->finalize = gtk_clist_finalize;
-
   widget_class->realize = gtk_clist_realize;
   widget_class->unrealize = gtk_clist_unrealize;
   widget_class->map = gtk_clist_map;
@@ -550,21 +682,34 @@ gtk_clist_class_init (GtkCListClass * klass)
   widget_class->focus_in_event = gtk_clist_focus_in;
   widget_class->focus_out_event = gtk_clist_focus_out;
   widget_class->draw_focus = gtk_clist_draw_focus;
+  widget_class->style_set = gtk_clist_style_set;
+  widget_class->drag_begin = gtk_clist_drag_begin;
+  widget_class->drag_end = gtk_clist_drag_end;
+  widget_class->drag_motion = gtk_clist_drag_motion;
+  widget_class->drag_leave = gtk_clist_drag_leave;
+  widget_class->drag_drop = gtk_clist_drag_drop;
+  widget_class->drag_data_get = gtk_clist_drag_data_get;
+  widget_class->drag_data_received = gtk_clist_drag_data_received;
 
   /* container_class->add = NULL; use the default GtkContainerClass warning */
-  /* container_class->remove = NULL; use the default GtkContainerClass warning */
+  /* container_class->remove=NULL; use the default GtkContainerClass warning */
+
   container_class->forall = gtk_clist_forall;
   container_class->focus = gtk_clist_focus;
   container_class->set_focus_child = gtk_clist_set_focus_child;
 
+  klass->set_scroll_adjustments = gtk_clist_set_scroll_adjustments;
+  klass->refresh = clist_refresh;
   klass->select_row = real_select_row;
   klass->unselect_row = real_unselect_row;
+  klass->row_move = real_row_move;
   klass->undo_selection = real_undo_selection;
   klass->resync_selection = resync_selection;
   klass->selection_find = selection_find;
   klass->click_column = NULL;
   klass->resize_column = real_resize_column;
   klass->draw_row = draw_row;
+  klass->draw_drag_highlight = draw_drag_highlight;
   klass->insert_row = real_insert_row;
   klass->remove_row = real_remove_row;
   klass->clear = real_clear;
@@ -581,221 +726,213 @@ gtk_clist_class_init (GtkCListClass * klass)
   klass->end_selection = end_selection;
   klass->abort_column_resize = abort_column_resize;
   klass->set_cell_contents = set_cell_contents;
+  klass->cell_size_request = cell_size_request;
+
+  binding_set = gtk_binding_set_by_class (klass);
+  gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
+                               "scroll_vertical", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
+                               "scroll_vertical", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
+                               "scroll_vertical", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
+                               "scroll_vertical", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
+                               "scroll_vertical", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
+                               "scroll_vertical", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
+                               GTK_TYPE_FLOAT, 1.0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
+                               "extend_selection", 3,
+                               GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
+                               GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
+                               "extend_selection", 3,
+                               GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
+                               GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
+                               "extend_selection", 3,
+                               GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
+                               GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
+                               "extend_selection", 3,
+                               GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
+                               GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_Home,
+                               GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+                               "extend_selection", 3,
+                               GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
+                               GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_End,
+                               GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+                               "extend_selection", 3,
+                               GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
+                               GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
+                               "scroll_horizontal", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
+                               "scroll_horizontal", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
+                               "scroll_horizontal", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
+                               GTK_TYPE_FLOAT, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
+                               "scroll_horizontal", 2,
+                               GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
+                               GTK_TYPE_FLOAT, 1.0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
+                               "undo_selection", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
+                               "abort_column_resize", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
+                               "toggle_focus_row", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
+                               "toggle_add_mode", 0);
+  gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
+                               "select_all", 0);
+  gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
+                               "unselect_all", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
+                               GDK_RELEASE_MASK | GDK_SHIFT_MASK,
+                               "end_selection", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
+                               GDK_RELEASE_MASK | GDK_SHIFT_MASK,
+                               "end_selection", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
+                               GDK_RELEASE_MASK | GDK_SHIFT_MASK |
+                               GDK_CONTROL_MASK,
+                               "end_selection", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
+                               GDK_RELEASE_MASK | GDK_SHIFT_MASK |
+                               GDK_CONTROL_MASK,
+                               "end_selection", 0);
+}
 
-  klass->scrollbar_spacing = 5;
+static void
+gtk_clist_set_arg (GtkObject      *object,
+                  GtkArg         *arg,
+                  guint           arg_id)
+{
+  GtkCList *clist;
 
-  {
-    GtkBindingSet *binding_set;
-
-    binding_set = gtk_binding_set_by_class (klass);
-    gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 1.0);
-
-    gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_Home,
-                                 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_End,
-                                 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
-
-
-    gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 1.0);
-
-
-    gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
-                                 "undo_selection", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
-                                 "abort_column_resize", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
-                                 "toggle_focus_row", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
-                                 "toggle_add_mode", 0);
-    gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
-                                 "select_all", 0);
-    gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
-                                 "unselect_all", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
-                                 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
-                                 "end_selection", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
-                                 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
-                                 "end_selection", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
-                                 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
-                                 GDK_CONTROL_MASK,
-                                 "end_selection", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
-                                 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
-                                 GDK_CONTROL_MASK,
-                                 "end_selection", 0);
-  }
+  clist = GTK_CLIST (object);
 
-  /*
-  {
-    GtkBindingSet *binding_set;
-
-    binding_set = gtk_binding_set_by_class (klass);
-    gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
-                                 "scroll_vertical", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0);
-
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
-                                 "extend_selection", 3,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
-
-    gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
-                                 "scroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 0.0);
-    gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
-                                 "sroll_horizontal", 2,
-                                 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
-                                  GTK_TYPE_FLOAT, 1.0);
-
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
-                                 "undo_selection", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
-                                 "abort_column_resize", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
-                                 "toggle_focus_row", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
-                                 "toggle_add_mode", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
-                                 "select_all", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
-                                 "unselect_all", 0);
-    gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
-                                 "end_selection", 0);
-  }
-  */
+  switch (arg_id)
+    {
+    case ARG_N_COLUMNS: /* construct-only arg, only set when !GTK_CONSTRUCTED */
+      gtk_clist_construct (clist, MAX (1, GTK_VALUE_UINT (*arg)), NULL);
+      break;
+    case ARG_SHADOW_TYPE:
+      gtk_clist_set_shadow_type (clist, GTK_VALUE_ENUM (*arg));
+      break;
+    case ARG_SELECTION_MODE:
+      gtk_clist_set_selection_mode (clist, GTK_VALUE_ENUM (*arg));
+      break;
+    case ARG_ROW_HEIGHT:
+      gtk_clist_set_row_height (clist, GTK_VALUE_UINT (*arg));
+      break;
+    case ARG_REORDERABLE:
+      gtk_clist_set_reorderable (clist, GTK_VALUE_BOOL (*arg));
+      break;
+    case ARG_TITLES_ACTIVE:
+      if (GTK_VALUE_BOOL (*arg))
+       gtk_clist_column_titles_active (clist);
+      else
+       gtk_clist_column_titles_passive (clist);
+      break;
+    case ARG_USE_DRAG_ICONS:
+      gtk_clist_set_use_drag_icons (clist, GTK_VALUE_BOOL (*arg));
+      break;
+    case ARG_SORT_TYPE:
+      gtk_clist_set_sort_type (clist, GTK_VALUE_ENUM (*arg));
+      break;
+    }
 }
 
 static void
-gtk_clist_init (GtkCList * clist)
+gtk_clist_get_arg (GtkObject      *object,
+                  GtkArg         *arg,
+                  guint           arg_id)
+{
+  GtkCList *clist;
+
+  clist = GTK_CLIST (object);
+
+  switch (arg_id)
+    {
+      guint i;
+
+    case ARG_N_COLUMNS:
+      GTK_VALUE_UINT (*arg) = clist->columns;
+      break;
+    case ARG_SHADOW_TYPE:
+      GTK_VALUE_ENUM (*arg) = clist->shadow_type;
+      break;
+    case ARG_SELECTION_MODE:
+      GTK_VALUE_ENUM (*arg) = clist->selection_mode;
+      break;
+    case ARG_ROW_HEIGHT:
+      GTK_VALUE_UINT (*arg) = GTK_CLIST_ROW_HEIGHT_SET(clist) ? clist->row_height : 0;
+      break;
+    case ARG_REORDERABLE:
+      GTK_VALUE_BOOL (*arg) = GTK_CLIST_REORDERABLE (clist);
+      break;
+    case ARG_TITLES_ACTIVE:
+      GTK_VALUE_BOOL (*arg) = TRUE;
+      for (i = 0; i < clist->columns; i++)
+       if (clist->column[i].button &&
+           !GTK_WIDGET_SENSITIVE (clist->column[i].button))
+         {
+           GTK_VALUE_BOOL (*arg) = FALSE;
+           break;
+         }
+      break;
+    case ARG_USE_DRAG_ICONS:
+      GTK_VALUE_BOOL (*arg) = GTK_CLIST_USE_DRAG_ICONS (clist);
+      break;
+    case ARG_SORT_TYPE:
+      GTK_VALUE_ENUM (*arg) = clist->sort_type;
+      break;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+    }
+}
+
+static void
+gtk_clist_init (GtkCList *clist)
 {
   clist->flags = 0;
 
   GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
-  GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
+  GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
+  GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
+  GTK_CLIST_SET_FLAG (clist, CLIST_DRAW_DRAG_LINE);
+  GTK_CLIST_SET_FLAG (clist, CLIST_USE_DRAG_ICONS);
 
   clist->row_mem_chunk = NULL;
   clist->cell_mem_chunk = NULL;
 
+  clist->freeze_count = 0;
+
   clist->rows = 0;
   clist->row_center_offset = 0;
   clist->row_height = 0;
@@ -818,8 +955,14 @@ gtk_clist_init (GtkCList * clist)
   clist->voffset = 0;
 
   clist->shadow_type = GTK_SHADOW_IN;
-  clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
-  clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
+  clist->vadjustment = NULL;
+  clist->hadjustment = NULL;
+
+  clist->button_actions[0] = GTK_BUTTON_SELECTS | GTK_BUTTON_DRAGS;
+  clist->button_actions[1] = GTK_BUTTON_IGNORED;
+  clist->button_actions[2] = GTK_BUTTON_IGNORED;
+  clist->button_actions[3] = GTK_BUTTON_IGNORED;
+  clist->button_actions[4] = GTK_BUTTON_IGNORED;
 
   clist->cursor_drag = NULL;
   clist->xor_gc = NULL;
@@ -833,8 +976,6 @@ gtk_clist_init (GtkCList * clist)
   clist->undo_selection = NULL;
   clist->undo_unselection = NULL;
 
-  GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
-  GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
   clist->focus_row = -1;
   clist->undo_anchor = -1;
 
@@ -844,6 +985,9 @@ gtk_clist_init (GtkCList * clist)
   clist->htimer = 0;
   clist->vtimer = 0;
 
+  clist->click_cell.row = -1;
+  clist->click_cell.column = -1;
+
   clist->compare = default_compare;
   clist->sort_type = GTK_SORT_ASCENDING;
   clist->sort_column = 0;
@@ -851,17 +995,17 @@ gtk_clist_init (GtkCList * clist)
 
 /* Constructors */
 void
-gtk_clist_construct (GtkCList * clist,
-                    gint columns,
-                    gchar *titles[])
+gtk_clist_construct (GtkCList *clist,
+                    gint      columns,
+                    gchar    *titles[])
 {
-  int i;
-
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
-  g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
+  g_return_if_fail (columns > 0);
+  g_return_if_fail (GTK_OBJECT_CONSTRUCTED (clist) == FALSE);
 
-  GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
+  /* mark the object as constructed */
+  gtk_object_constructed (GTK_OBJECT (clist));
 
   /* initalize memory chunks, if this has not been done by any
    * possibly derived widget
@@ -869,13 +1013,15 @@ gtk_clist_construct (GtkCList * clist,
   if (!clist->row_mem_chunk)
     clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
                                            sizeof (GtkCListRow),
-                                           sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE, 
+                                           sizeof (GtkCListRow) *
+                                           CLIST_OPTIMUM_SIZE, 
                                            G_ALLOC_AND_FREE);
 
   if (!clist->cell_mem_chunk)
     clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
                                             sizeof (GtkCell) * columns,
-                                            sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE, 
+                                            sizeof (GtkCell) * columns *
+                                            CLIST_OPTIMUM_SIZE, 
                                             G_ALLOC_AND_FREE);
 
   /* set number of columns, allocate memory */
@@ -887,11 +1033,10 @@ gtk_clist_construct (GtkCList * clist,
    * isn't there*/
   column_button_create (clist, 0);
 
-  /* create scrollbars */
-  create_scrollbars (clist);
-
   if (titles)
     {
+      guint i;
+      
       GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
       for (i = 0; i < columns; i++)
        gtk_clist_set_column_title (clist, i, titles[i]);
@@ -902,55 +1047,163 @@ gtk_clist_construct (GtkCList * clist,
     }
 }
 
-/*
- * GTKCLIST PUBLIC INTERFACE
- *   gtk_clist_new_with_titles
+/* GTKCLIST PUBLIC INTERFACE
  *   gtk_clist_new
+ *   gtk_clist_new_with_titles
+ *   gtk_clist_set_hadjustment
+ *   gtk_clist_set_vadjustment
+ *   gtk_clist_get_hadjustment
+ *   gtk_clist_get_vadjustment
+ *   gtk_clist_set_shadow_type
+ *   gtk_clist_set_selection_mode
+ *   gtk_clist_freeze
+ *   gtk_clist_thaw
  */
-GtkWidget *
-gtk_clist_new_with_titles (gint columns,
-                          gchar * titles[])
+GtkWidget*
+gtk_clist_new (gint columns)
+{
+  return gtk_clist_new_with_titles (columns, NULL);
+}
+GtkWidget*
+gtk_clist_new_with_titles (gint   columns,
+                          gchar *titles[])
 {
   GtkWidget *widget;
 
-  g_return_val_if_fail (titles != NULL, NULL);
-  
   widget = gtk_type_new (GTK_TYPE_CLIST);
-  
   gtk_clist_construct (GTK_CLIST (widget), columns, titles);
 
   return widget;
 }
 
-GtkWidget *
-gtk_clist_new (gint columns)
+void
+gtk_clist_set_hadjustment (GtkCList      *clist,
+                          GtkAdjustment *adjustment)
 {
-  GtkCList *clist;
+  GtkAdjustment *old_adjustment;
 
-  if (columns < 1)
-    return NULL;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  if (adjustment)
+    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+  
+  if (clist->hadjustment == adjustment)
+    return;
+  
+  old_adjustment = clist->hadjustment;
+
+  if (clist->hadjustment)
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (clist->hadjustment), clist);
+      gtk_object_unref (GTK_OBJECT (clist->hadjustment));
+    }
+
+  clist->hadjustment = adjustment;
+
+  if (clist->hadjustment)
+    {
+      gtk_object_ref (GTK_OBJECT (clist->hadjustment));
+      gtk_object_sink (GTK_OBJECT (clist->hadjustment));
+
+      gtk_signal_connect (GTK_OBJECT (clist->hadjustment), "changed",
+                         (GtkSignalFunc) hadjustment_changed,
+                         (gpointer) clist);
+      gtk_signal_connect (GTK_OBJECT (clist->hadjustment), "value_changed",
+                         (GtkSignalFunc) hadjustment_value_changed,
+                         (gpointer) clist);
+    }
+
+  if (!clist->hadjustment || !old_adjustment)
+    gtk_widget_queue_resize (GTK_WIDGET (clist));
+}
+
+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 clist->hadjustment;
+}
+
+void
+gtk_clist_set_vadjustment (GtkCList      *clist,
+                          GtkAdjustment *adjustment)
+{
+  GtkAdjustment *old_adjustment;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  if (adjustment)
+    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  if (clist->vadjustment == adjustment)
+    return;
+  
+  old_adjustment = clist->vadjustment;
+
+  if (clist->vadjustment)
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (clist->vadjustment), clist);
+      gtk_object_unref (GTK_OBJECT (clist->vadjustment));
+    }
+
+  clist->vadjustment = adjustment;
+
+  if (clist->vadjustment)
+    {
+      gtk_object_ref (GTK_OBJECT (clist->vadjustment));
+      gtk_object_sink (GTK_OBJECT (clist->vadjustment));
+
+      gtk_signal_connect (GTK_OBJECT (clist->vadjustment), "changed",
+                         (GtkSignalFunc) vadjustment_changed,
+                         (gpointer) clist);
+      gtk_signal_connect (GTK_OBJECT (clist->vadjustment), "value_changed",
+                         (GtkSignalFunc) vadjustment_value_changed,
+                         (gpointer) clist);
+    }
+
+  if (!clist->vadjustment || !old_adjustment)
+    gtk_widget_queue_resize (GTK_WIDGET (clist));
+}
 
-  clist = gtk_type_new (GTK_TYPE_CLIST);
-  gtk_clist_construct (clist, columns, NULL);
-  return GTK_WIDGET (clist);
+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 clist->vadjustment;
+}
+
+static void
+gtk_clist_set_scroll_adjustments (GtkCList      *clist,
+                                 GtkAdjustment *hadjustment,
+                                 GtkAdjustment *vadjustment)
+{
+  if (clist->hadjustment != hadjustment)
+    gtk_clist_set_hadjustment (clist, hadjustment);
+  if (clist->vadjustment != vadjustment)
+    gtk_clist_set_vadjustment (clist, vadjustment);
 }
 
 void
-gtk_clist_set_border (GtkCList * clist,
-                     GtkShadowType border)
+gtk_clist_set_shadow_type (GtkCList      *clist,
+                          GtkShadowType  type)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist->shadow_type = border;
+  clist->shadow_type = type;
 
   if (GTK_WIDGET_VISIBLE (clist))
     gtk_widget_queue_resize (GTK_WIDGET (clist));
 }
 
 void
-gtk_clist_set_selection_mode (GtkCList clist,
-                             GtkSelectionMode mode)
+gtk_clist_set_selection_mode (GtkCList         *clist,
+                             GtkSelectionMode  mode)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
@@ -982,242 +1235,182 @@ gtk_clist_set_selection_mode (GtkCList * clist,
 }
 
 void
-gtk_clist_freeze (GtkCList * clist)
+gtk_clist_freeze (GtkCList *clist)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
+  clist->freeze_count++;
 }
 
 void
-gtk_clist_thaw (GtkCList * clist)
+gtk_clist_thaw (GtkCList *clist)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
-
-  adjust_scrollbars (clist);
-  draw_rows (clist, NULL);
-}
-
+  if (clist->freeze_count)
+    {
+      clist->freeze_count--;
+      CLIST_REFRESH (clist);
+    }
+}
+
+/* PUBLIC COLUMN FUNCTIONS
+ *   gtk_clist_column_titles_show
+ *   gtk_clist_column_titles_hide
+ *   gtk_clist_column_title_active
+ *   gtk_clist_column_title_passive
+ *   gtk_clist_column_titles_active
+ *   gtk_clist_column_titles_passive
+ *   gtk_clist_set_column_title
+ *   gtk_clist_get_column_title
+ *   gtk_clist_set_column_widget
+ *   gtk_clist_set_column_justification
+ *   gtk_clist_set_column_visibility
+ *   gtk_clist_set_column_resizeable
+ *   gtk_clist_set_column_auto_resize
+ *   gtk_clist_optimal_column_width
+ *   gtk_clist_set_column_width
+ *   gtk_clist_set_column_min_width
+ *   gtk_clist_set_column_max_width
+ */
 void
-gtk_clist_column_titles_show (GtkCList * clist)
+gtk_clist_column_titles_show (GtkCList *clist)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (!GTK_CLIST_SHOW_TITLES (clist))
+  if (!GTK_CLIST_SHOW_TITLES(clist))
     {
       GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
       if (clist->title_window)
-             gdk_window_show (clist->title_window);
+       gdk_window_show (clist->title_window);
       gtk_widget_queue_resize (GTK_WIDGET (clist));
     }
 }
 
 void 
-gtk_clist_column_titles_hide (GtkCList * clist)
+gtk_clist_column_titles_hide (GtkCList *clist)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (GTK_CLIST_SHOW_TITLES (clist))
+  if (GTK_CLIST_SHOW_TITLES(clist))
     {
       GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
       if (clist->title_window)
-             gdk_window_hide (clist->title_window);
+       gdk_window_hide (clist->title_window);
       gtk_widget_queue_resize (GTK_WIDGET (clist));
     }
 }
 
 void
-gtk_clist_set_column_visibility (GtkCList *clist,
-                                gint      column,
-                                gboolean  visible)
+gtk_clist_column_title_active (GtkCList *clist,
+                              gint      column)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
   if (column < 0 || column >= clist->columns)
     return;
-  if (clist->column[column].visible == visible)
+  if (!clist->column[column].button || !clist->column[column].button_passive)
     return;
 
-  /* don't hide last visible column */
-  if (!visible)
-    {
-      gint i;
-      gint vis_columns = 0;
-
-      for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
-       if (clist->column[i].visible)
-         vis_columns++;
+  clist->column[column].button_passive = FALSE;
 
-      if (vis_columns < 2)
-       return;
-    }
+  gtk_signal_disconnect_by_func (GTK_OBJECT (clist->column[column].button),
+                                (GtkSignalFunc) column_title_passive_func,
+                                NULL);
 
-  clist->column[column].visible = visible;
-  if (visible)
-    gtk_widget_show (clist->column[column].button);
-  else
-    gtk_widget_hide (clist->column[column].button);
+  GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS);
+  if (GTK_WIDGET_VISIBLE (clist))
+    gtk_widget_queue_draw (clist->column[column].button);
 }
 
 void
-gtk_clist_set_column_resizeable (GtkCList *clist,
-                                gint      column,
-                                gint      resizeable)
+gtk_clist_column_title_passive (GtkCList *clist,
+                               gint      column)
 {
+  GtkButton *button;
+
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
   if (column < 0 || column >= clist->columns)
     return;
-  if (clist->column[column].resizeable == resizeable)
+  if (!clist->column[column].button || clist->column[column].button_passive)
     return;
 
-  clist->column[column].resizeable = resizeable;
-
-  if (GTK_WIDGET_VISIBLE (clist))
-    size_allocate_title_buttons (clist);
-}
+  button = GTK_BUTTON (clist->column[column].button);
 
-void
-gtk_clist_set_column_min_width (GtkCList *clist,
-                               gint      column,
-                               gint      min_width)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  clist->column[column].button_passive = TRUE;
 
-  if (column < 0 || column >= clist->columns)
-    return;
-  if (clist->column[column].min_width == min_width)
-    return;
+  if (button->button_down)
+    gtk_button_released (button);
+  if (button->in_button)
+    gtk_button_leave (button);
 
-  if (clist->column[column].max_width >= 0  &&
-      clist->column[column].max_width < min_width)
-    clist->column[column].min_width = clist->column[column].max_width;
-  else
-    clist->column[column].min_width = min_width;
+  gtk_signal_connect (GTK_OBJECT (clist->column[column].button), "event",
+                     (GtkSignalFunc) column_title_passive_func, NULL);
 
-  if (clist->column[column].area.width < clist->column[column].min_width)
-    gtk_clist_set_column_width (clist, column,clist->column[column].min_width);
+  GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS);
+  if (GTK_WIDGET_VISIBLE (clist))
+    gtk_widget_queue_draw (clist->column[column].button);
 }
 
 void
-gtk_clist_set_column_max_width (GtkCList * clist,
-                               gint column,
-                               gint max_width)
+gtk_clist_column_titles_active (GtkCList *clist)
 {
+  gint i;
+
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (column < 0 || column >= clist->columns)
-    return;
-  if (clist->column[column].max_width == max_width)
+  if (!GTK_CLIST_SHOW_TITLES(clist))
     return;
 
-  if (clist->column[column].min_width >= 0 && max_width >= 0 &&
-      clist->column[column].min_width > max_width)
-    clist->column[column].max_width = clist->column[column].min_width;
-  else
-    clist->column[column].max_width = max_width;
-  
-  if (clist->column[column].area.width > clist->column[column].max_width)
-    gtk_clist_set_column_width (clist, column,clist->column[column].max_width);
+  for (i = 0; i < clist->columns; i++)
+    gtk_clist_column_title_active (clist, i);
 }
 
 void
-gtk_clist_column_title_active (GtkCList * clist,
-                              gint column)
+gtk_clist_column_titles_passive (GtkCList *clist)
 {
+  gint i;
+
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (column < 0 || column >= clist->columns)
+  if (!GTK_CLIST_SHOW_TITLES(clist))
     return;
 
-  if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
-      !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
-    {
-      GTK_WIDGET_SET_FLAGS (clist->column[column].button,
-                           GTK_SENSITIVE | GTK_CAN_FOCUS);
-      if (GTK_WIDGET_VISIBLE (clist))
-       gtk_widget_queue_draw (clist->column[column].button);
-    }
+  for (i = 0; i < clist->columns; i++)
+    gtk_clist_column_title_passive (clist, i);
 }
 
 void
-gtk_clist_column_title_passive (GtkCList * clist,
-                               gint column)
+gtk_clist_set_column_title (GtkCList    *clist,
+                           gint         column,
+                           const gchar *title)
 {
+  gint new_button = 0;
+  GtkWidget *old_widget;
+  GtkWidget *alignment = NULL;
+  GtkWidget *label;
+
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
   if (column < 0 || column >= clist->columns)
     return;
 
-  if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
-      GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
+  /* if the column button doesn't currently exist,
+   * it has to be created first */
+  if (!clist->column[column].button)
     {
-      GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
-      if (GTK_WIDGET_VISIBLE (clist))
-       gtk_widget_queue_draw (clist->column[column].button);
-    }
-}
-
-void
-gtk_clist_column_titles_active (GtkCList * clist)
-{
-  gint i;
-
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].button)
-      gtk_clist_column_title_active (clist, i);
-}
-
-void
-gtk_clist_column_titles_passive (GtkCList * clist)
-{
-  gint i;
-
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].button)
-      gtk_clist_column_title_passive (clist, i);
-}
-
-void
-gtk_clist_set_column_title (GtkCList    *clist,
-                           gint         column,
-                           const gchar *title)
-{
-  gint new_button = 0;
-  GtkWidget *old_widget;
-  GtkWidget *alignment = NULL;
-  GtkWidget *label;
-
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-
-  if (column < 0 || column >= clist->columns)
-    return;
-
-  /* if the column button doesn't currently exist,
-   * it has to be created first */
-  if (!clist->column[column].button)
-    {
-      column_button_create (clist, column);
-      new_button = 1;
+      column_button_create (clist, column);
+      new_button = 1;
     }
 
   column_title_new (clist, column, title);
@@ -1247,7 +1440,9 @@ gtk_clist_set_column_title (GtkCList    *clist,
       break;
     }
 
+  gtk_widget_push_composite_child ();
   label = gtk_label_new (clist->column[column].title);
+  gtk_widget_pop_composite_child ();
   gtk_container_add (GTK_CONTAINER (alignment), label);
   gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
   gtk_widget_show (label);
@@ -1259,10 +1454,23 @@ gtk_clist_set_column_title (GtkCList    *clist,
     size_allocate_title_buttons (clist);
 }
 
+gchar *
+gtk_clist_get_column_title (GtkCList *clist,
+                           gint      column)
+{
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
+
+  if (column < 0 || column >= clist->columns)
+    return NULL;
+
+  return clist->column[column].title;
+}
+
 void
-gtk_clist_set_column_widget (GtkCList clist,
-                            gint column,
-                            GtkWidget * widget)
+gtk_clist_set_column_widget (GtkCList  *clist,
+                            gint       column,
+                            GtkWidget *widget)
 {
   gint new_button = 0;
   GtkWidget *old_widget;
@@ -1286,7 +1494,8 @@ gtk_clist_set_column_widget (GtkCList * clist,
   /* remove and destroy the old widget */
   old_widget = GTK_BIN (clist->column[column].button)->child;
   if (old_widget)
-    gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
+    gtk_container_remove (GTK_CONTAINER (clist->column[column].button),
+                         old_widget);
 
   /* add and show the widget */
   if (widget)
@@ -1301,10 +1510,26 @@ gtk_clist_set_column_widget (GtkCList * clist,
     size_allocate_title_buttons (clist);
 }
 
+GtkWidget *
+gtk_clist_get_column_widget (GtkCList *clist,
+                            gint      column)
+{
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
+
+  if (column < 0 || column >= clist->columns)
+    return NULL;
+
+  if (clist->column[column].button)
+    return GTK_BUTTON (clist->column[column].button)->child;
+
+  return NULL;
+}
+
 void
-gtk_clist_set_column_justification (GtkCList clist,
-                                   gint column,
-                                   GtkJustification justification)
+gtk_clist_set_column_justification (GtkCList         *clist,
+                                   gint              column,
+                                   GtkJustification  justification)
 {
   GtkWidget *alignment;
 
@@ -1345,4563 +1570,5180 @@ gtk_clist_set_column_justification (GtkCList * clist,
        }
     }
 
-  if (!GTK_CLIST_FROZEN (clist))
+  if (CLIST_UNFROZEN (clist))
     draw_rows (clist, NULL);
 }
 
-static void
-real_resize_column (GtkCList * clist,
-                   gint column,
-                   gint width)
+void
+gtk_clist_set_column_visibility (GtkCList *clist,
+                                gint      column,
+                                gboolean  visible)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
   if (column < 0 || column >= clist->columns)
     return;
+  if (clist->column[column].visible == visible)
+    return;
 
-  if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
-    width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
-  if (clist->column[column].max_width >= 0 &&
-      width > clist->column[column].max_width)
-    width = clist->column[column].max_width;
-  
-  clist->column[column].width = width;
-  clist->column[column].width_set = TRUE;
+  /* don't hide last visible column */
+  if (!visible)
+    {
+      gint i;
+      gint vis_columns = 0;
 
-  /* FIXME: this is quite expensive to do if the widget hasn't
-   *        been size_allocated yet, and pointless. Should
-   *        a flag be kept
-   */
-  size_allocate_columns (clist);
-  size_allocate_title_buttons (clist);
+      for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
+       if (clist->column[i].visible)
+         vis_columns++;
+
+      if (vis_columns < 2)
+       return;
+    }
 
-  if (!GTK_CLIST_FROZEN (clist))
+  clist->column[column].visible = visible;
+
+  if (clist->column[column].button)
     {
-      adjust_scrollbars (clist);
-      draw_rows (clist, NULL);
+      if (visible)
+       gtk_widget_show (clist->column[column].button);
+      else
+       gtk_widget_hide (clist->column[column].button);
     }
+  
+  gtk_widget_queue_resize (GTK_WIDGET(clist));
 }
 
 void
-gtk_clist_set_column_width (GtkCList * clist,
-                           gint column,
-                           gint width)
+gtk_clist_set_column_resizeable (GtkCList *clist,
+                                gint      column,
+                                gboolean  resizeable)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
   if (column < 0 || column >= clist->columns)
     return;
+  if (clist->column[column].resizeable == resizeable)
+    return;
 
-  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN],
-                  column, width);
+  clist->column[column].resizeable = resizeable;
+  if (resizeable)
+    clist->column[column].auto_resize = FALSE;
+
+  if (GTK_WIDGET_VISIBLE (clist))
+    size_allocate_title_buttons (clist);
 }
 
 void
-gtk_clist_set_row_height (GtkCList * clist,
-                         gint height)
+gtk_clist_set_column_auto_resize (GtkCList *clist,
+                                 gint      column,
+                                 gboolean  auto_resize)
 {
-  gint text_height;
-
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (height > 0)
-    clist->row_height = height;
-  else
+  if (column < 0 || column >= clist->columns)
+    return;
+  if (clist->column[column].auto_resize == auto_resize)
     return;
 
-  GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
-  
-  if (GTK_WIDGET_REALIZED (clist))
-    {
-      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))
+  clist->column[column].auto_resize = auto_resize;
+  if (auto_resize)
     {
-      adjust_scrollbars (clist);
-      draw_rows (clist, NULL);
+      clist->column[column].resizeable = FALSE;
+      if (!GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+       {
+         gint width;
+
+         width = gtk_clist_optimal_column_width (clist, column);
+         gtk_clist_set_column_width (clist, column, width);
+       }
     }
+
+  if (GTK_WIDGET_VISIBLE (clist))
+    size_allocate_title_buttons (clist);
 }
 
-void
-gtk_clist_moveto (GtkCList * clist,
-                 gint row,
-                 gint column,
-                 gfloat row_align,
-                 gfloat col_align)
+gint
+gtk_clist_columns_autosize (GtkCList *clist)
 {
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-
-  if (row < -1 || row >= clist->rows)
-    return;
-  if (column < -1 || column >= clist->columns)
-    return;
+  gint i;
+  gint width;
 
-  row_align = CLAMP (row_align, 0, 1);
-  col_align = CLAMP (col_align, 0, 1);
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
 
-  /* adjust horizontal scrollbar */
-  if (column >= 0)
+  gtk_clist_freeze (clist);
+  width = 0;
+  for (i = 0; i < clist->columns; i++)
     {
-      GtkAdjustment *adj;
-      gint x;
+      gtk_clist_set_column_width (clist, i,
+                                 gtk_clist_optimal_column_width (clist, i));
 
-      adj = GTK_RANGE (clist->hscrollbar)->adjustment;
-
-      x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
-       (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
-                     CELL_SPACING - clist->column[column].area.width));
-      if (x < 0)
-       gtk_adjustment_set_value (adj, 0.0);
-      else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
-       gtk_adjustment_set_value 
-         (adj, LIST_WIDTH (clist) - clist->clist_window_width);
-      else
-       gtk_adjustment_set_value (adj, x);
+      width += clist->column[i].width;
     }
 
-  /* adjust vertical scrollbar */
-  if (row >= 0)
-    move_vertical (clist, row, row_align);
+  gtk_clist_thaw (clist);
+  return width;
 }
 
-GtkCellType 
-gtk_clist_get_cell_type (GtkCList * clist,
-                        gint row,
-                        gint column)
+gint
+gtk_clist_optimal_column_width (GtkCList *clist,
+                               gint      column)
 {
-  GtkCListRow *clist_row;
+  GtkRequisition requisition;
+  GList *list;
+  gint width;
 
-  g_return_val_if_fail (clist != NULL, -1);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_CLIST (clist), 0);
 
-  if (row < 0 || row >= clist->rows)
-    return -1;
-  if (column < 0 || column >= clist->columns)
-    return -1;
+  if (column < 0 || column > clist->columns)
+    return 0;
+
+  if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[column].button)
+    width = (clist->column[column].button->requisition.width)
+#if 0
+            (CELL_SPACING + (2 * COLUMN_INSET)))
+#endif
+               ;
+  else
+    width = 0;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+  for (list = clist->row_list; list; list = list->next)
+    {
+      GTK_CLIST_CLASS_FW (clist)->cell_size_request
+       (clist, GTK_CLIST_ROW (list), column, &requisition);
+      width = MAX (width, requisition.width);
+    }
 
-  return clist_row->cell[column].type;
+  return width;
 }
 
 void
-gtk_clist_set_text (GtkCList    *clist,
-                   gint         row,
-                   gint         column,
-                   const gchar *text)
+gtk_clist_set_column_width (GtkCList *clist,
+                           gint      column,
+                           gint      width)
 {
-  GtkCListRow *clist_row;
-
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  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 */
-  GTK_CLIST_CLASS_FW (clist)->set_cell_contents
-    (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
-
-  /* redraw the list if it's not frozen */
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
-       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
-    }
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN],
+                  column, width);
 }
 
-gint
-gtk_clist_get_text (GtkCList * clist,
-                   gint row,
-                   gint column,
-                   gchar ** text)
+void
+gtk_clist_set_column_min_width (GtkCList *clist,
+                               gint      column,
+                               gint      min_width)
 {
-  GtkCListRow *clist_row;
-
-  g_return_val_if_fail (clist != NULL, 0);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (row < 0 || row >= clist->rows)
-    return 0;
   if (column < 0 || column >= clist->columns)
-    return 0;
-
-  clist_row = (g_list_nth (clist->row_list, row))->data;
-
-  if (clist_row->cell[column].type != GTK_CELL_TEXT)
-    return 0;
+    return;
+  if (clist->column[column].min_width == min_width)
+    return;
 
-  if (text)
-    *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
+  if (clist->column[column].max_width >= 0  &&
+      clist->column[column].max_width < min_width)
+    clist->column[column].min_width = clist->column[column].max_width;
+  else
+    clist->column[column].min_width = min_width;
 
-  return 1;
+  if (clist->column[column].area.width < clist->column[column].min_width)
+    gtk_clist_set_column_width (clist, column,clist->column[column].min_width);
 }
 
 void
-gtk_clist_set_pixmap (GtkCList * clist,
-                     gint row,
-                     gint column,
-                     GdkPixmap * pixmap,
-                     GdkBitmap * mask)
+gtk_clist_set_column_max_width (GtkCList *clist,
+                               gint      column,
+                               gint      max_width)
 {
-  GtkCListRow *clist_row;
-
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (row < 0 || row >= clist->rows)
-    return;
   if (column < 0 || column >= clist->columns)
     return;
+  if (clist->column[column].max_width == max_width)
+    return;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
-  
-  gdk_pixmap_ref (pixmap);
-  
-  if (mask) gdk_pixmap_ref (mask);
+  if (clist->column[column].min_width >= 0 && max_width >= 0 &&
+      clist->column[column].min_width > max_width)
+    clist->column[column].max_width = clist->column[column].min_width;
+  else
+    clist->column[column].max_width = max_width;
   
-  GTK_CLIST_CLASS_FW (clist)->set_cell_contents
-    (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
-
-  /* redraw the list if it's not frozen */
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
-       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
-    }
+  if (clist->column[column].area.width > clist->column[column].max_width)
+    gtk_clist_set_column_width (clist, column,clist->column[column].max_width);
 }
 
-gint
-gtk_clist_get_pixmap (GtkCList * clist,
-                     gint row,
-                     gint column,
-                     GdkPixmap ** pixmap,
-                     GdkBitmap ** mask)
-{
-  GtkCListRow *clist_row;
-
-  g_return_val_if_fail (clist != NULL, 0);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
+/* PRIVATE COLUMN FUNCTIONS
+ *   column_auto_resize
+ *   real_resize_column
+ *   abort_column_resize
+ *   size_allocate_title_buttons
+ *   size_allocate_columns
+ *   list_requisition_width
+ *   new_column_width
+ *   column_button_create
+ *   column_button_clicked
+ *   column_title_passive_func
+ */
+static void
+column_auto_resize (GtkCList    *clist,
+                   GtkCListRow *clist_row,
+                   gint         column,
+                   gint         old_width)
+{
+  /* resize column if needed for auto_resize */
+  GtkRequisition requisition;
 
-  if (row < 0 || row >= clist->rows)
-    return 0;
-  if (column < 0 || column >= clist->columns)
-    return 0;
+  if (!clist->column[column].auto_resize ||
+      GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    return;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+  if (clist_row)
+    GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
+                                                  column, &requisition);
+  else
+    requisition.width = 0;
 
-  if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
-    return 0;
+  if (requisition.width > clist->column[column].width)
+    gtk_clist_set_column_width (clist, column, requisition.width);
+  else if (requisition.width < old_width &&
+          old_width == clist->column[column].width)
+    {
+      GList *list;
+      gint new_width = 0;
 
-  if (pixmap)
-  {
-    *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
-    /* mask can be NULL */
-    *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
-  }
+      /* run a "gtk_clist_optimal_column_width" but break, if
+       * the column doesn't shrink */
+      if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[column].button)
+       new_width = (clist->column[column].button->requisition.width -
+                    (CELL_SPACING + (2 * COLUMN_INSET)));
+      else
+       new_width = 0;
 
-  return 1;
+      for (list = clist->row_list; list; list = list->next)
+       {
+         GTK_CLIST_CLASS_FW (clist)->cell_size_request
+           (clist, GTK_CLIST_ROW (list), column, &requisition);
+         new_width = MAX (new_width, requisition.width);
+         if (new_width == clist->column[column].width)
+           break;
+       }
+      if (new_width < clist->column[column].width)
+       gtk_clist_set_column_width
+         (clist, column, MAX (new_width, clist->column[column].min_width));
+    }
 }
 
-void
-gtk_clist_set_pixtext (GtkCList    *clist,
-                      gint         row,
-                      gint         column,
-                      const gchar *text,
-                      guint8       spacing,
-                      GdkPixmap   *pixmap,
-                      GdkBitmap   *mask)
+static void
+real_resize_column (GtkCList *clist,
+                   gint      column,
+                   gint      width)
 {
-  GtkCListRow *clist_row;
-
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  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);
-  if (mask) gdk_pixmap_ref (mask);
-  GTK_CLIST_CLASS_FW (clist)->set_cell_contents
-    (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
-
-  /* redraw the list if it's not frozen */
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
-       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
-    }
-}
-
-gint
-gtk_clist_get_pixtext (GtkCList * clist,
-                      gint row,
-                      gint column,
-                      gchar ** text,
-                      guint8 * spacing,
-                      GdkPixmap ** pixmap,
-                      GdkBitmap ** mask)
-{
-  GtkCListRow *clist_row;
-
-  g_return_val_if_fail (clist != NULL, 0);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
-
-  if (row < 0 || row >= clist->rows)
-    return 0;
-  if (column < 0 || column >= clist->columns)
-    return 0;
-
-  clist_row = (g_list_nth (clist->row_list, row))->data;
-
-  if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
-    return 0;
+  if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
+    width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
+  if (clist->column[column].max_width >= 0 &&
+      width > clist->column[column].max_width)
+    width = clist->column[column].max_width;
 
-  if (text)
-    *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
-  if (spacing)
-    *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
-  if (pixmap)
-    *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
+  clist->column[column].width = width;
+  clist->column[column].width_set = TRUE;
 
-  /* mask can be NULL */
-  *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
+  /* FIXME: this is quite expensive to do if the widget hasn't
+   *        been size_allocated yet, and pointless. Should
+   *        a flag be kept
+   */
+  size_allocate_columns (clist, TRUE);
+  size_allocate_title_buttons (clist);
 
-  return 1;
+  CLIST_REFRESH (clist);
 }
 
-void
-gtk_clist_set_foreground (GtkCList * clist,
-                         gint row,
-                         GdkColor * color)
+static void
+abort_column_resize (GtkCList *clist)
 {
-  GtkCListRow *clist_row;
-
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (row < 0 || row >= clist->rows)
+  if (!GTK_CLIST_IN_DRAG(clist))
     return;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+  GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
+  gtk_grab_remove (GTK_WIDGET (clist));
+  gdk_pointer_ungrab (GDK_CURRENT_TIME);
+  clist->drag_pos = -1;
 
-  if (color)
+  if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
+    draw_xor_line (clist);
+
+  if (GTK_CLIST_ADD_MODE(clist))
     {
-      clist_row->foreground = *color;
-      clist_row->fg_set = TRUE;
+      gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
+      gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
     }
-  else
-    clist_row->fg_set = FALSE;
-
-  if (!GTK_CLIST_FROZEN (clist)
-      && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
-    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
 }
 
-void
-gtk_clist_set_background (GtkCList * clist,
-                         gint row,
-                         GdkColor * color)
+static void
+size_allocate_title_buttons (GtkCList *clist)
 {
-  GtkCListRow *clist_row;
-
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  GtkAllocation button_allocation;
+  gint last_column;
+  gint last_button = 0;
+  gint i;
 
-  if (row < 0 || row >= clist->rows)
+  if (!GTK_WIDGET_REALIZED (clist))
     return;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+  button_allocation.x = clist->hoffset;
+  button_allocation.y = 0;
+  button_allocation.width = 0;
+  button_allocation.height = clist->column_title_area.height;
 
-  if (color)
+  /* find last visible column */
+  for (last_column = clist->columns - 1; last_column >= 0; last_column--)
+    if (clist->column[last_column].visible)
+      break;
+
+  for (i = 0; i < last_column; i++)
     {
-      clist_row->background = *color;
-      clist_row->bg_set = TRUE;
-    }
-  else
-    clist_row->bg_set = FALSE;
+      if (!clist->column[i].visible)
+       {
+         last_button = i + 1;
+         gdk_window_hide (clist->column[i].window);
+         continue;
+       }
 
-  if (!GTK_CLIST_FROZEN (clist)
-      && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
-    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
-}
+      button_allocation.width += (clist->column[i].area.width +
+                                 CELL_SPACING + 2 * COLUMN_INSET);
 
-void
-gtk_clist_set_shift (GtkCList * clist,
-                    gint row,
-                    gint column,
-                    gint vertical,
-                    gint horizontal)
-{
-  GtkCListRow *clist_row;
+      if (!clist->column[i + 1].button)
+       {
+         gdk_window_hide (clist->column[i].window);
+         continue;
+       }
 
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+      gtk_widget_size_allocate (clist->column[last_button].button,
+                               &button_allocation);
+      button_allocation.x += button_allocation.width;
+      button_allocation.width = 0;
 
-  if (row < 0 || row >= clist->rows)
-    return;
-  if (column < 0 || column >= clist->columns)
-    return;
+      if (clist->column[last_button].resizeable)
+       {
+         gdk_window_show (clist->column[last_button].window);
+         gdk_window_move_resize (clist->column[last_button].window,
+                                 button_allocation.x - (DRAG_WIDTH / 2), 
+                                 0, DRAG_WIDTH,
+                                 clist->column_title_area.height);
+       }
+      else
+       gdk_window_hide (clist->column[last_button].window);
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+      last_button = i + 1;
+    }
 
-  clist_row->cell[column].vertical = vertical;
-  clist_row->cell[column].horizontal = horizontal;
+  button_allocation.width += (clist->column[last_column].area.width +
+                             2 * (CELL_SPACING + COLUMN_INSET));
+  gtk_widget_size_allocate (clist->column[last_button].button,
+                           &button_allocation);
 
-  if (!GTK_CLIST_FROZEN (clist)
-      && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
-    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+  if (clist->column[last_button].resizeable)
+    {
+      button_allocation.x += button_allocation.width;
+
+      gdk_window_show (clist->column[last_button].window);
+      gdk_window_move_resize (clist->column[last_button].window,
+                             button_allocation.x - (DRAG_WIDTH / 2), 
+                             0, DRAG_WIDTH, clist->column_title_area.height);
+    }
+  else
+    gdk_window_hide (clist->column[last_button].window);
 }
 
-void
-gtk_clist_set_selectable (GtkCList    *clist,
-                         gint         row,
-                         gboolean     selectable)
+static void
+size_allocate_columns (GtkCList *clist,
+                      gboolean  block_resize)
 {
-  GtkCListRow *clist_row;
-
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-
-  if (row < 0 || row >= clist->rows)
-    return;
+  gint xoffset = CELL_SPACING + COLUMN_INSET;
+  gint last_column;
+  gint i;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+  /* find last visible column and calculate correct column width */
+  for (last_column = clist->columns - 1;
+       last_column >= 0 && !clist->column[last_column].visible; last_column--);
 
-  if (selectable == clist_row->selectable)
+  if (last_column < 0)
     return;
 
-  clist_row->selectable = selectable;
-
-  if (!selectable && clist_row->state == GTK_STATE_SELECTED)
+  for (i = 0; i <= last_column; i++)
     {
-      if (clist->anchor >= 0 &&
-         clist->selection_mode == GTK_SELECTION_EXTENDED)
+      if (!clist->column[i].visible)
+       continue;
+      clist->column[i].area.x = xoffset;
+      if (clist->column[i].width_set)
        {
-         if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)))
+         if (!block_resize && GTK_CLIST_SHOW_TITLES(clist) &&
+             clist->column[i].auto_resize && clist->column[i].button)
            {
-             GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
-             gtk_grab_remove (GTK_WIDGET (clist));
-             gdk_pointer_ungrab (GDK_CURRENT_TIME);
-             if (clist->htimer)
-               {
-                 gtk_timeout_remove (clist->htimer);
-                 clist->htimer = 0;
-               }
-             if (clist->vtimer)
-               {
-                 gtk_timeout_remove (clist->vtimer);
-                 clist->vtimer = 0;
-               }
+             gint width;
+
+             width = (clist->column[i].button->requisition.width -
+                      (CELL_SPACING + (2 * COLUMN_INSET)));
+
+             if (width > clist->column[i].width)
+               gtk_clist_set_column_width (clist, i, width);
            }
-         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+
+         clist->column[i].area.width = clist->column[i].width;
+         xoffset += clist->column[i].width + CELL_SPACING + (2* COLUMN_INSET);
        }
-      unselect_row (clist, row, -1, NULL);
-    }      
+      else if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[i].button)
+       {
+         clist->column[i].area.width =
+           clist->column[i].button->requisition.width -
+           (CELL_SPACING + (2 * COLUMN_INSET));
+         xoffset += clist->column[i].button->requisition.width;
+       }
+    }
+
+  clist->column[last_column].area.width = clist->column[last_column].area.width
+    + MAX (0, clist->clist_window_width + COLUMN_INSET - xoffset);
 }
 
-gboolean
-gtk_clist_get_selectable (GtkCList *clist,
-                         gint      row)
+static gint
+list_requisition_width (GtkCList *clist) 
 {
-  g_return_val_if_fail (clist != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
+  gint width = CELL_SPACING;
+  gint i;
 
-  if (row < 0 || row >= clist->rows)
-    return FALSE;
+  for (i = clist->columns - 1; i >= 0; i--)
+    {
+      if (!clist->column[i].visible)
+       continue;
 
-  return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable;
-}
+      if (clist->column[i].width_set)
+       width += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
+      else if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[i].button)
+       width += clist->column[i].button->requisition.width;
+    }
 
-gint
-gtk_clist_prepend (GtkCList *clist,
-                  gchar    *text[])
-{
-  g_return_val_if_fail (clist != NULL, -1);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
-  g_return_val_if_fail (text != NULL, -1);
-
-  return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text);
+  return width;
 }
 
-gint
-gtk_clist_append (GtkCList *clist,
-                 gchar    *text[])
+/* this function returns the new width of the column being resized given
+ * the column and x position of the cursor; the x cursor position is passed
+ * in as a pointer and automagicly corrected if it's beyond min/max limits */
+static gint
+new_column_width (GtkCList *clist,
+                 gint      column,
+                 gint     *x)
 {
-  g_return_val_if_fail (clist != NULL, -1);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
-  g_return_val_if_fail (text != NULL, -1);
+  gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness;
+  gint width;
+  gint cx;
+  gint dx;
+  gint last_column;
 
-  return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
+  /* first translate the x position from widget->window
+   * to clist->clist_window */
+  cx = *x - xthickness;
+
+  for (last_column = clist->columns - 1;
+       last_column >= 0 && !clist->column[last_column].visible; last_column--);
+
+  /* calculate new column width making sure it doesn't end up
+   * less than the minimum width */
+  dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
+       (column < last_column) * CELL_SPACING);
+  width = cx - dx;
+
+  if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
+    {
+      width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
+      cx = dx + width;
+      *x = cx + xthickness;
+    }
+  else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
+          width > clist->column[column].max_width)
+    {
+      width = clist->column[column].max_width;
+      cx = dx + clist->column[column].max_width;
+      *x = cx + xthickness;
+    }      
+
+  if (cx < 0 || cx > clist->clist_window_width)
+    *x = -1;
+
+  return width;
 }
 
-gint
-gtk_clist_insert (GtkCList *clist,
-                 gint      row,
-                 gchar    *text[])
+static void
+column_button_create (GtkCList *clist,
+                     gint      column)
 {
-  g_return_val_if_fail (clist != NULL, -1);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
-  g_return_val_if_fail (text != NULL, -1);
+  GtkWidget *button;
 
-  if (row < 0 || row > clist->rows)
-    row = clist->rows;
+  gtk_widget_push_composite_child ();
+  button = clist->column[column].button = gtk_button_new ();
+  gtk_widget_pop_composite_child ();
 
-  return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
+  if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
+    gtk_widget_set_parent_window (clist->column[column].button,
+                                 clist->title_window);
+  gtk_widget_set_parent (button, GTK_WIDGET (clist));
+
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     (GtkSignalFunc) column_button_clicked,
+                     (gpointer) clist);
+  gtk_widget_show (button);
 }
 
-static gint
-real_insert_row (GtkCList *clist,
-                gint      row,
-                gchar    *text[])
+static void
+column_button_clicked (GtkWidget *widget,
+                      gpointer   data)
 {
   gint i;
-  GtkCListRow *clist_row;
-
-  g_return_val_if_fail (clist != NULL, -1);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
-  g_return_val_if_fail (text != NULL, -1);
+  GtkCList *clist;
 
-  /* return if out of bounds */
-  if (row < 0 || row > clist->rows)
-    return -1;
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (data));
 
-  /* create the row */
-  clist_row = row_new (clist);
+  clist = GTK_CLIST (data);
 
-  /* set the text in the row's columns */
+  /* find the column who's button was pressed */
   for (i = 0; i < clist->columns; i++)
-    if (text[i])
-      GTK_CLIST_CLASS_FW (clist)->set_cell_contents
-       (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
+    if (clist->column[i].button == widget)
+      break;
 
-  if (!clist->rows)
-    {
-      clist->row_list = g_list_append (clist->row_list, clist_row);
-      clist->row_list_end = clist->row_list;
-    }
-  else
-    {
-      if (GTK_CLIST_AUTO_SORT (clist))   /* override insertion pos */
-       {
-         GList *work;
-         
-         row = 0;
-         work = clist->row_list;
-         
-         if (clist->sort_type == GTK_SORT_ASCENDING)
-           {
-             while (row < clist->rows &&
-                    clist->compare (clist, clist_row,
-                                    GTK_CLIST_ROW (work)) > 0)
-               {
-                 row++;
-                 work = work->next;
-               }
-           }
-         else
-           {
-             while (row < clist->rows &&
-                    clist->compare (clist, clist_row,
-                                    GTK_CLIST_ROW (work)) < 0)
-               {
-                 row++;
-                 work = work->next;
-               }
-           }
-       }
-      
-      /* 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);
-    }
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
+}
+
+static gint
+column_title_passive_func (GtkWidget *widget, 
+                          GdkEvent  *event,
+                          gpointer   data)
+{
+  g_return_val_if_fail (event != NULL, FALSE);
   
-  clist->rows++;
+  switch (event->type)
+    {
+    case GDK_MOTION_NOTIFY:
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+      return TRUE;
+    default:
+      break;
+    }
+  return FALSE;
+}
 
-  if (row < ROW_FROM_YPIXEL (clist, 0))
-    clist->voffset -= (clist->row_height + CELL_SPACING);
 
-  /* syncronize the selection list */
-  sync_selection (clist, row, SYNC_INSERT);
+/* PUBLIC CELL FUNCTIONS
+ *   gtk_clist_get_cell_type
+ *   gtk_clist_set_text
+ *   gtk_clist_get_text
+ *   gtk_clist_set_pixmap
+ *   gtk_clist_get_pixmap
+ *   gtk_clist_set_pixtext
+ *   gtk_clist_get_pixtext
+ *   gtk_clist_set_shift
+ */
+GtkCellType 
+gtk_clist_get_cell_type (GtkCList *clist,
+                        gint      row,
+                        gint      column)
+{
+  GtkCListRow *clist_row;
 
-  /* redraw the list if it isn't frozen */
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      adjust_scrollbars (clist);
+  g_return_val_if_fail (clist != NULL, -1);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
 
-      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
-       draw_rows (clist, NULL);
-    }
+  if (row < 0 || row >= clist->rows)
+    return -1;
+  if (column < 0 || column >= clist->columns)
+    return -1;
 
-  return row;
-}
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-void
-gtk_clist_remove (GtkCList * clist,
-                 gint row)
-{
-  GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
+  return clist_row->cell[column].type;
 }
 
-static void
-real_remove_row (GtkCList * clist,
-                gint row)
+void
+gtk_clist_set_text (GtkCList    *clist,
+                   gint         row,
+                   gint         column,
+                   const gchar *text)
 {
-  gint was_visible, was_selected;
-  GList *list;
   GtkCListRow *clist_row;
 
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  /* return if out of bounds */
-  if (row < 0 || row > (clist->rows - 1))
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
     return;
 
-  was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
-  was_selected = 0;
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  /* get the row we're going to delete */
-  list = g_list_nth (clist->row_list, row);
-  clist_row = list->data;
+  /* if text is null, then the cell is empty */
+  GTK_CLIST_CLASS_FW (clist)->set_cell_contents
+    (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
 
-  /* if we're removing a selected row, we have to make sure
-   * it's properly unselected, and then sync up the clist->selected
-   * list to reflect the deincrimented indexies of rows after the
-   * removal */
-  if (clist_row->state == GTK_STATE_SELECTED)
+  /* redraw the list if it's not frozen */
+  if (CLIST_UNFROZEN (clist))
     {
-      switch (clist->selection_mode)
-       {
-       case GTK_SELECTION_SINGLE:
-       case GTK_SELECTION_MULTIPLE:
-       case GTK_SELECTION_EXTENDED:
-         unselect_row (clist, row, -1, NULL);
-         break;
-
-       case GTK_SELECTION_BROWSE:
-         select_row (clist, row - 1, -1, NULL);
-         break;
-
-       default:
-         break;
-       }
+      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
     }
+}
 
-  /* 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;
-  if (row >= clist->focus_row && clist->focus_row >=0)
-    clist->focus_row--;
+gint
+gtk_clist_get_text (GtkCList  *clist,
+                   gint       row,
+                   gint       column,
+                   gchar    **text)
+{
+  GtkCListRow *clist_row;
 
-  clist->row_list = g_list_remove (clist->row_list, clist_row);
-  clist->rows--;
-  
-  if (row < ROW_FROM_YPIXEL (clist, 0))
-    clist->voffset += clist->row_height + CELL_SPACING;
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
 
-  sync_selection (clist, row, SYNC_REMOVE);
+  if (row < 0 || row >= clist->rows)
+    return 0;
+  if (column < 0 || column >= clist->columns)
+    return 0;
 
-  /* toast the row */
-  row_delete (clist, clist_row);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  /* redraw the row if it isn't frozen */
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      adjust_scrollbars (clist);
+  if (clist_row->cell[column].type != GTK_CELL_TEXT)
+    return 0;
 
-      if (was_visible)
-       draw_rows (clist, NULL);
-    }
+  if (text)
+    *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
+
+  return 1;
 }
 
-static void
-sync_selection (GtkCList * clist,
-               gint row,
-               gint mode)
+void
+gtk_clist_set_pixmap (GtkCList  *clist,
+                     gint       row,
+                     gint       column,
+                     GdkPixmap *pixmap,
+                     GdkBitmap *mask)
 {
-  GList *list;
-  gint d;
-
-  if (mode == SYNC_INSERT)
-    d = 1;
-  else
-    d = -1;
-      
-  if (clist->focus_row >= row)
-    {
-      clist->focus_row += d;
-      if (clist->focus_row == -1 && clist->rows >= 1)
-       clist->focus_row = 0;
-    }
-
-  if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
-    GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
-
-  g_list_free (clist->undo_selection);
-  g_list_free (clist->undo_unselection);
-  clist->undo_selection = NULL;
-  clist->undo_unselection = NULL;
-
-  clist->anchor = -1;
-  clist->drag_pos = -1;
-  clist->undo_anchor = clist->focus_row;
-
-  list = clist->selection;
-  while (list)
-    {
-      if (GPOINTER_TO_INT (list->data) >= row)
-       list->data = ((gchar*) list->data) + d;
-      list = list->next;
-    }
-}
-
-void
-gtk_clist_clear (GtkCList * clist)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-  
-  GTK_CLIST_CLASS_FW (clist)->clear (clist);
-}
-
-static void
-real_clear (GtkCList * clist)
-{
-  GList *list, *free_list;
+  GtkCListRow *clist_row;
 
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  /* free up the selection list */
-  g_list_free (clist->selection);
-  g_list_free (clist->undo_selection);
-  g_list_free (clist->undo_unselection);
-
-  clist->selection = NULL;
-  clist->selection_end = NULL;
-  clist->undo_selection = NULL;
-  clist->undo_unselection = NULL;
-  clist->voffset = 0;
-  clist->focus_row = -1;
-  clist->anchor = -1;
-  clist->undo_anchor = -1;
-  clist->anchor_state = GTK_STATE_SELECTED;
-  clist->drag_pos = -1;
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
 
-  /* remove all the rows */
-  free_list = clist->row_list;
-  clist->row_list = NULL;
-  clist->row_list_end = NULL;
-  clist->rows = 0;
-  for (list = free_list; list; list = list->next)
-    row_delete (clist, GTK_CLIST_ROW (list));
-  g_list_free (free_list);
+  clist_row = ROW_ELEMENT (clist, row)->data;
+  
+  gdk_pixmap_ref (pixmap);
+  
+  if (mask) gdk_pixmap_ref (mask);
+  
+  GTK_CLIST_CLASS_FW (clist)->set_cell_contents
+    (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
 
-  /* zero-out the scrollbars */
-  if (clist->vscrollbar)
+  /* redraw the list if it's not frozen */
+  if (CLIST_UNFROZEN (clist))
     {
-      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_thaw (clist);
+      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
     }
 }
 
-void 
-gtk_clist_swap_rows (GtkCList * clist,
-                    gint row1, 
-                    gint row2)
+gint
+gtk_clist_get_pixmap (GtkCList   *clist,
+                     gint        row,
+                     gint        column,
+                     GdkPixmap **pixmap,
+                     GdkBitmap **mask)
 {
-  gint first, last;
-  GList *list, *link1, *link2;
-  gpointer swap;
-  
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-
-  if (GTK_CLIST_AUTO_SORT (clist))
-    return;
-
-  if (row1 < 0 || row1 > (clist->rows - 1))
-    return;
+  GtkCListRow *clist_row;
 
-  if (row2 < 0 || row2 > (clist->rows - 1))
-    return;
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
 
-  first = MIN (row1, row2);
-  last = MAX (row1, row2);
+  if (row < 0 || row >= clist->rows)
+    return 0;
+  if (column < 0 || column >= clist->columns)
+    return 0;
 
-  link1 = g_list_nth (clist->row_list, first);
-  link2 = g_list_nth (link1, row2 - row1);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  swap = link1->data;
-  link1->data = link2->data;
-  link2->data = swap;
-  
-  list = clist->selection;
-  while (list)
-    {
-      if (GPOINTER_TO_INT (list->data) == row1)
-       list->data = GINT_TO_POINTER (row2);
-      
-      if (GPOINTER_TO_INT (list->data) == row2)
-       list->data = GINT_TO_POINTER (row1);
-      
-      list = list->next;
-    }
-  
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
-       GTK_CLIST_CLASS_FW (clist)->draw_row
-         (clist, NULL, row1, GTK_CLIST_ROW (link2));
+  if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
+    return 0;
 
-      if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
-       GTK_CLIST_CLASS_FW (clist)->draw_row
-         (clist, NULL, row2, GTK_CLIST_ROW (link1));
-    }
-}
+  if (pixmap)
+  {
+    *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
+    /* mask can be NULL */
+    *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
+  }
 
-void
-gtk_clist_set_row_data (GtkCList * clist,
-                       gint row,
-                       gpointer data)
-{
-  gtk_clist_set_row_data_full (clist, row, data, NULL);
+  return 1;
 }
 
 void
-gtk_clist_set_row_data_full (GtkCList * clist,
-                            gint row,
-                            gpointer data,
-                            GtkDestroyNotify destroy)
+gtk_clist_set_pixtext (GtkCList    *clist,
+                      gint         row,
+                      gint         column,
+                      const gchar *text,
+                      guint8       spacing,
+                      GdkPixmap   *pixmap,
+                      GdkBitmap   *mask)
 {
   GtkCListRow *clist_row;
 
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (row < 0 || row > (clist->rows - 1))
+  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->data = data;
-  clist_row->destroy = destroy;
-}
-
-gpointer
-gtk_clist_get_row_data (GtkCList * clist,
-                       gint row)
-{
-  GtkCListRow *clist_row;
-
-  g_return_val_if_fail (clist != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
-
-  if (row < 0 || row > (clist->rows - 1))
-    return NULL;
+  clist_row = ROW_ELEMENT (clist, row)->data;
+  
+  gdk_pixmap_ref (pixmap);
+  if (mask) gdk_pixmap_ref (mask);
+  GTK_CLIST_CLASS_FW (clist)->set_cell_contents
+    (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
-  return clist_row->data;
+  /* redraw the list if it's not frozen */
+  if (CLIST_UNFROZEN (clist))
+    {
+      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+    }
 }
 
 gint
-gtk_clist_find_row_from_data (GtkCList * clist,
-                             gpointer data)
+gtk_clist_get_pixtext (GtkCList   *clist,
+                      gint        row,
+                      gint        column,
+                      gchar     **text,
+                      guint8     *spacing,
+                      GdkPixmap **pixmap,
+                      GdkBitmap **mask)
 {
-  GList *list;
-  gint n;
-
-  g_return_val_if_fail (clist != NULL, -1);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
+  GtkCListRow *clist_row;
 
-  if (clist->rows < 1)
-    return -1; /* is this an optimization or just worthless? */
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
 
-  for (n = 0, list = clist->row_list; list; n++, list = list->next)
-    if (GTK_CLIST_ROW (list)->data == data)
-      return n;
+  if (row < 0 || row >= clist->rows)
+    return 0;
+  if (column < 0 || column >= clist->columns)
+    return 0;
 
-  return -1;
-}
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-void
-gtk_clist_select_row (GtkCList * clist,
-                     gint row,
-                     gint column)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
+    return 0;
 
-  if (row < 0 || row >= clist->rows)
-    return;
+  if (text)
+    *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
+  if (spacing)
+    *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
+  if (pixmap)
+    *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
 
-  if (column < -1 || column >= clist->columns)
-    return;
+  /* mask can be NULL */
+  *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
 
-  select_row (clist, row, column, NULL);
+  return 1;
 }
 
 void
-gtk_clist_unselect_row (GtkCList * clist,
-                       gint row,
-                       gint column)
+gtk_clist_set_shift (GtkCList *clist,
+                    gint      row,
+                    gint      column,
+                    gint      vertical,
+                    gint      horizontal)
 {
+  GtkRequisition requisition = { 0 };
+  GtkCListRow *clist_row;
+
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
   if (row < 0 || row >= clist->rows)
     return;
-
-  if (column < -1 || column >= clist->columns)
+  if (column < 0 || column >= clist->columns)
     return;
 
-  unselect_row (clist, row, column, NULL);
-}
-
-GtkVisibility
-gtk_clist_row_is_visible (GtkCList * clist,
-                         gint row)
-{
-  gint top;
-
-  g_return_val_if_fail (clist != NULL, 0);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
-
-  if (row < 0 || row >= clist->rows)
-    return GTK_VISIBILITY_NONE;
-
-  if (clist->row_height == 0)
-    return GTK_VISIBILITY_NONE;
-
-  if (row < ROW_FROM_YPIXEL (clist, 0))
-    return GTK_VISIBILITY_NONE;
-
-  if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
-    return GTK_VISIBILITY_NONE;
-
-  top = ROW_TOP_YPIXEL (clist, row);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  if ((top < 0)
-      || ((top + clist->row_height) >= clist->clist_window_height))
-    return GTK_VISIBILITY_PARTIAL;
+  if (clist->column[column].auto_resize &&
+      !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
+                                                  column, &requisition);
 
-  return GTK_VISIBILITY_FULL;
-}
+  clist_row->cell[column].vertical = vertical;
+  clist_row->cell[column].horizontal = horizontal;
 
-#if 0
-static 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);
+  column_auto_resize (clist, clist_row, column, requisition.width);
 
-  return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
+  if (CLIST_UNFROZEN (clist) && gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
 }
 
-static GtkAdjustment*
-gtk_clist_get_hadjustment (GtkCList * clist)
+/* PRIVATE CELL FUNCTIONS
+ *   set_cell_contents
+ *   cell_size_request
+ */
+static void
+set_cell_contents (GtkCList    *clist,
+                  GtkCListRow *clist_row,
+                  gint         column,
+                  GtkCellType  type,
+                  const gchar *text,
+                  guint8       spacing,
+                  GdkPixmap   *pixmap,
+                  GdkBitmap   *mask)
 {
-  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));
-}
-#endif
+  GtkRequisition requisition;
 
-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));
+  g_return_if_fail (clist_row != NULL);
 
-  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->column[column].auto_resize &&
+      !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
+                                                  column, &requisition);
 
-  if (clist->hscrollbar_policy != hscrollbar_policy)
+  switch (clist_row->cell[column].type)
     {
-      clist->hscrollbar_policy = hscrollbar_policy;
-
-      if (GTK_WIDGET (clist)->parent)
-       gtk_widget_queue_resize (GTK_WIDGET (clist));
-    }
-}
-
-void
-gtk_clist_undo_selection (GtkCList *clist)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+    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);
+      if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
+       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);
+      if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
+       gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
+      break;
+    case GTK_CELL_WIDGET:
+      /* unimplimented */
+      break;
+    default:
+      break;
+    }
 
-  if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
-      (clist->undo_selection || clist->undo_unselection))
-    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
+  clist_row->cell[column].type = GTK_CELL_EMPTY;
+
+  switch (type)
+    {
+    case GTK_CELL_TEXT:
+      if (text)
+       {
+         clist_row->cell[column].type = GTK_CELL_TEXT;
+         GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
+       }
+      break;
+    case GTK_CELL_PIXMAP:
+      if (pixmap)
+       {
+         clist_row->cell[column].type = GTK_CELL_PIXMAP;
+         GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
+         /* We set the mask even if it is NULL */
+         GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
+       }
+      break;
+    case GTK_CELL_PIXTEXT:
+      if (text && pixmap)
+       {
+         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;
+       }
+      break;
+    default:
+      break;
+    }
+
+  if (clist->column[column].auto_resize &&
+      !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    column_auto_resize (clist, clist_row, column, requisition.width);
 }
 
 static void
-real_undo_selection (GtkCList *clist)
+cell_size_request (GtkCList       *clist,
+                  GtkCListRow    *clist_row,
+                  gint            column,
+                  GtkRequisition *requisition)
 {
-  GList *work;
+  GtkStyle *style;
+  gint width;
+  gint height;
 
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
+  g_return_if_fail (requisition != NULL);
 
-  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
-      clist->selection_mode != GTK_SELECTION_EXTENDED)
-    return;
-
-  if (clist->anchor >= 0)
-    GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+  get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style,
+                 NULL, NULL);
 
-  if (!(clist->undo_selection || clist->undo_unselection))
+  switch (clist_row->cell[column].type)
     {
-      gtk_clist_unselect_all (clist);
-      return;
+    case GTK_CELL_TEXT:
+      requisition->width =
+       gdk_string_width (style->font,
+                         GTK_CELL_TEXT (clist_row->cell[column])->text);
+      requisition->height = style->font->ascent + style->font->descent;
+      break;
+    case GTK_CELL_PIXTEXT:
+      gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap,
+                          &width, &height);
+      requisition->width = width +
+       GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing +
+       gdk_string_width (style->font,
+                         GTK_CELL_TEXT (clist_row->cell[column])->text);
+
+      requisition->height = MAX (style->font->ascent + style->font->descent,
+                                height);
+      break;
+    case GTK_CELL_PIXMAP:
+      gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap,
+                          &width, &height);
+      requisition->width = width;
+      requisition->height = height;
+      break;
+    default:
+      requisition->width  = 0;
+      requisition->height = 0;
+      break;
     }
 
-  for (work = clist->undo_selection; work; work = work->next)
-    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
-                    GPOINTER_TO_INT (work->data), -1, NULL);
+  requisition->width  += clist_row->cell[column].horizontal;
+  requisition->height += clist_row->cell[column].vertical;
+}
 
-  for (work = clist->undo_unselection; work; work = work->next)
-    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 
-                    GPOINTER_TO_INT (work->data), -1, NULL);
+/* PUBLIC INSERT/REMOVE ROW FUNCTIONS
+ *   gtk_clist_prepend
+ *   gtk_clist_append
+ *   gtk_clist_insert
+ *   gtk_clist_remove
+ *   gtk_clist_clear
+ */
+gint
+gtk_clist_prepend (GtkCList    *clist,
+                  gchar       *text[])
+{
+  g_return_val_if_fail (clist != NULL, -1);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
+  g_return_val_if_fail (text != NULL, -1);
 
-  if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
-    {
-      gtk_clist_draw_focus (GTK_WIDGET (clist));
-      clist->focus_row = clist->undo_anchor;
-      gtk_clist_draw_focus (GTK_WIDGET (clist));
-    }
-  else
-    clist->focus_row = clist->undo_anchor;
-  
-  clist->undo_anchor = -1;
-  g_list_free (clist->undo_selection);
-  g_list_free (clist->undo_unselection);
-  clist->undo_selection = NULL;
-  clist->undo_unselection = NULL;
+  return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text);
+}
 
-  if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
-      clist->clist_window_height)
-    gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
-  else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
-    gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+gint
+gtk_clist_append (GtkCList    *clist,
+                 gchar       *text[])
+{
+  g_return_val_if_fail (clist != NULL, -1);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
 }
 
-/*
- * GTKOBJECT
- *   gtk_clist_destroy
- *   gtk_clist_finalize
+gint
+gtk_clist_insert (GtkCList    *clist,
+                 gint         row,
+                 gchar       *text[])
+{
+  g_return_val_if_fail (clist != NULL, -1);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  if (row < 0 || row > clist->rows)
+    row = clist->rows;
+
+  return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
+}
+
+void
+gtk_clist_remove (GtkCList *clist,
+                 gint      row)
+{
+  GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
+}
+
+void
+gtk_clist_clear (GtkCList *clist)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  
+  GTK_CLIST_CLASS_FW (clist)->clear (clist);
+}
+
+/* PRIVATE INSERT/REMOVE ROW FUNCTIONS
+ *   real_insert_row
+ *   real_remove_row
+ *   real_clear
+ *   real_row_move
  */
-static void
-gtk_clist_destroy (GtkObject * object)
+static gint
+real_insert_row (GtkCList *clist,
+                gint      row,
+                gchar    *text[])
 {
   gint i;
-  GtkCList *clist;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (GTK_IS_CLIST (object));
+  GtkCListRow *clist_row;
 
-  clist = GTK_CLIST (object);
+  g_return_val_if_fail (clist != NULL, -1);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
+  g_return_val_if_fail (text != NULL, -1);
 
-  /* freeze the list */
-  GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
+  /* return if out of bounds */
+  if (row < 0 || row > clist->rows)
+    return -1;
 
-  /* get rid of all the rows */
-  gtk_clist_clear (clist);
+  /* create the row */
+  clist_row = row_new (clist);
 
-  /* Since we don't have a _remove method, unparent the children
-   * instead of destroying them so the focus will be unset properly.
-   * (For other containers, the _remove method takes care of the
-   * unparent) The destroy will happen when the refcount drops
-   * to zero.
-   */
+  /* set the text in the row's columns */
+  for (i = 0; i < clist->columns; i++)
+    if (text[i])
+      GTK_CLIST_CLASS_FW (clist)->set_cell_contents
+       (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
 
-  /* destroy the scrollbars */
-  if (clist->vscrollbar)
+  if (!clist->rows)
     {
-      gtk_widget_unparent (clist->vscrollbar);
-      clist->vscrollbar = NULL;
+      clist->row_list = g_list_append (clist->row_list, clist_row);
+      clist->row_list_end = clist->row_list;
     }
-  if (clist->hscrollbar)
+  else
     {
-      gtk_widget_unparent (clist->hscrollbar);
-      clist->hscrollbar = NULL;
+      if (GTK_CLIST_AUTO_SORT(clist))   /* override insertion pos */
+       {
+         GList *work;
+         
+         row = 0;
+         work = clist->row_list;
+         
+         if (clist->sort_type == GTK_SORT_ASCENDING)
+           {
+             while (row < clist->rows &&
+                    clist->compare (clist, clist_row,
+                                    GTK_CLIST_ROW (work)) > 0)
+               {
+                 row++;
+                 work = work->next;
+               }
+           }
+         else
+           {
+             while (row < clist->rows &&
+                    clist->compare (clist, clist_row,
+                                    GTK_CLIST_ROW (work)) < 0)
+               {
+                 row++;
+                 work = work->next;
+               }
+           }
+       }
+      
+      /* 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++;
 
-  if (clist->htimer)
+  if (row < ROW_FROM_YPIXEL (clist, 0))
+    clist->voffset -= (clist->row_height + CELL_SPACING);
+
+  /* syncronize the selection list */
+  sync_selection (clist, row, SYNC_INSERT);
+
+  if (clist->rows == 1)
     {
-      gtk_timeout_remove (clist->htimer);
-      clist->htimer = 0;
+      clist->focus_row = 0;
+      if (clist->selection_mode == GTK_SELECTION_BROWSE)
+       gtk_clist_select_row (clist, 0, -1);
     }
-  if (clist->vtimer)
+
+  /* redraw the list if it isn't frozen */
+  if (CLIST_UNFROZEN (clist))
     {
-      gtk_timeout_remove (clist->vtimer);
-      clist->vtimer = 0;
-    }
+      adjust_adjustments (clist, FALSE);
 
-  /* destroy the column buttons */
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].button)
-      {
-       gtk_widget_unparent (clist->column[i].button);
-       clist->column[i].button = NULL;
-      }
+      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+       draw_rows (clist, NULL);
+    }
 
-  if (GTK_OBJECT_CLASS (parent_class)->destroy)
-    (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+  return row;
 }
 
 static void
-gtk_clist_finalize (GtkObject * object)
+real_remove_row (GtkCList *clist,
+                gint      row)
 {
-  GtkCList *clist;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (GTK_IS_CLIST (object));
+  gint was_visible, was_selected;
+  GList *list;
+  GtkCListRow *clist_row;
 
-  clist = GTK_CLIST (object);
-
-  columns_delete (clist);
-
-  g_mem_chunk_destroy (clist->cell_mem_chunk);
-  g_mem_chunk_destroy (clist->row_mem_chunk);
-
-  if (GTK_OBJECT_CLASS (parent_class)->finalize)
-    (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
-/*
- * GTKWIDGET
- *   gtk_clist_realize
- *   gtk_clist_unrealize
- *   gtk_clist_map
- *   gtk_clist_unmap
- *   gtk_clist_draw
- *   gtk_clist_expose
- *   gtk_clist_button_press
- *   gtk_clist_button_release
- *   gtk_clist_motion
- *   gtk_clist_size_request
- *   gtk_clist_size_allocate
- */
-static void
-gtk_clist_realize (GtkWidget * widget)
-{
-  gint i;
-  GtkCList *clist;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  GdkGCValues values;
-  gint border_width;
-
-  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);
-
-  add_style_data (clist);
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-  
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = widget->allocation.x + border_width;
-  attributes.y = widget->allocation.y + border_width;
-  attributes.width = widget->allocation.width - border_width * 2;
-  attributes.height = widget->allocation.height - border_width * 2;
-  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 |
-                           GDK_KEY_RELEASE_MASK);
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  /* main window */
-  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
-  gdk_window_set_user_data (widget->window, clist);
+  /* return if out of bounds */
+  if (row < 0 || row > (clist->rows - 1))
+    return;
 
-  widget->style = gtk_style_attach (widget->style, widget->window);
+  was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
+  was_selected = 0;
 
-  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+  /* get the row we're going to delete */
+  list = ROW_ELEMENT (clist, row);
+  g_assert (list != NULL);
+  clist_row = list->data;
 
-  /* column-title window */
+  /* if we're removing a selected row, we have to make sure
+   * it's properly unselected, and then sync up the clist->selected
+   * list to reflect the deincrimented indexies of rows after the
+   * removal */
+  if (clist_row->state == GTK_STATE_SELECTED)
+    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
+                    row, -1, NULL);
 
-  attributes.x = clist->column_title_area.x;
-  attributes.y = clist->column_title_area.y;
-  attributes.width = clist->column_title_area.width;
-  attributes.height = clist->column_title_area.height;
-  
-  clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
-  gdk_window_set_user_data (clist->title_window, clist);
+  /* reset the row end pointer if we're removing at the end of the list */
+  clist->rows--;
+  if (clist->row_list == list)
+    clist->row_list = g_list_next (list);
+  if (clist->row_list_end == list)
+    clist->row_list_end = g_list_previous (list);
+  g_list_remove (list, clist_row);
 
-  gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
-  gdk_window_show (clist->title_window);
+  /*if (clist->focus_row >=0 &&
+      (row <= clist->focus_row || clist->focus_row >= clist->rows))
+      clist->focus_row--;*/
 
-  /* set things up so column buttons are drawn in title window */
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].button)
-      gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
+  if (row < ROW_FROM_YPIXEL (clist, 0))
+    clist->voffset += clist->row_height + CELL_SPACING;
 
-  /* clist-window */
-  attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
-  attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
-    clist->column_title_area.height;
-  attributes.width = clist->clist_window_width;
-  attributes.height = clist->clist_window_height;
-  
-  clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
-  gdk_window_set_user_data (clist->clist_window, clist);
+  sync_selection (clist, row, SYNC_REMOVE);
 
-  gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
-  gdk_window_show (clist->clist_window);
-  gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
-                      &clist->clist_window_height);
+  if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
+      clist->focus_row >= 0)
+    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                    clist->focus_row, -1, NULL);
 
-  /* create resize windows */
-  attributes.wclass = GDK_INPUT_ONLY;
-  attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
-                          GDK_BUTTON_RELEASE_MASK |
-                          GDK_POINTER_MOTION_MASK |
-                          GDK_POINTER_MOTION_HINT_MASK |
-                          GDK_KEY_PRESS_MASK);
-  attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
-  attributes_mask = GDK_WA_CURSOR;
-  
-  attributes.x =  LIST_WIDTH (clist) + 1;
-  attributes.y = 0;
-  attributes.width = 0;
-  attributes.height = 0;
+  /* toast the row */
+  row_delete (clist, clist_row);
 
-  for (i = 0; i < clist->columns; i++)
+  /* redraw the row if it isn't frozen */
+  if (CLIST_UNFROZEN (clist))
     {
-      clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
-      gdk_window_set_user_data (clist->column[i].window, clist);
-    }
-
-  /* This is slightly less efficient than creating them with the
-   * right size to begin with, but easier
-   */
-  size_allocate_title_buttons (clist);
-
-  /* GCs */
-  clist->fg_gc = gdk_gc_new (widget->window);
-  clist->bg_gc = gdk_gc_new (widget->window);
-  
-  /* We'll use this gc to do scrolling as well */
-  gdk_gc_set_exposures (clist->fg_gc, TRUE);
+      adjust_adjustments (clist, FALSE);
 
-  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);
+      if (was_visible)
+       draw_rows (clist, NULL);
+    }
 }
 
 static void
-gtk_clist_unrealize (GtkWidget * widget)
+real_clear (GtkCList *clist)
 {
+  GList *list;
+  GList *free_list;
   gint i;
-  GtkCList *clist;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (widget));
 
-  clist = GTK_CLIST (widget);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
+  /* free up the selection list */
+  g_list_free (clist->selection);
+  g_list_free (clist->undo_selection);
+  g_list_free (clist->undo_unselection);
 
-  gdk_cursor_destroy (clist->cursor_drag);
-  gdk_gc_destroy (clist->xor_gc);
-  gdk_gc_destroy (clist->fg_gc);
-  gdk_gc_destroy (clist->bg_gc);
+  clist->selection = NULL;
+  clist->selection_end = NULL;
+  clist->undo_selection = NULL;
+  clist->undo_unselection = NULL;
+  clist->voffset = 0;
+  clist->focus_row = -1;
+  clist->anchor = -1;
+  clist->undo_anchor = -1;
+  clist->anchor_state = GTK_STATE_SELECTED;
+  clist->drag_pos = -1;
 
+  /* remove all the rows */
+  GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
+  free_list = clist->row_list;
+  clist->row_list = NULL;
+  clist->row_list_end = NULL;
+  clist->rows = 0;
+  for (list = free_list; list; list = list->next)
+    row_delete (clist, GTK_CLIST_ROW (list));
+  g_list_free (free_list);
+  GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
   for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].window)
+    if (clist->column[i].auto_resize)
       {
-       gdk_window_set_user_data (clist->column[i].window, NULL);
-       gdk_window_destroy (clist->column[i].window);
-       clist->column[i].window = NULL;
+       if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[i].button)
+         gtk_clist_set_column_width
+           (clist, i, (clist->column[i].button->requisition.width -
+                       (CELL_SPACING + (2 * COLUMN_INSET))));
+       else
+         gtk_clist_set_column_width (clist, i, 0);
       }
-
-  gdk_window_set_user_data (clist->clist_window, NULL);
-  gdk_window_destroy (clist->clist_window);
-  clist->clist_window = NULL;
-
-  gdk_window_set_user_data (clist->title_window, NULL);
-  gdk_window_destroy (clist->title_window);
-  clist->title_window = NULL;
-
-  clist->cursor_drag = NULL;
-  clist->xor_gc = NULL;
-  clist->fg_gc = NULL;
-  clist->bg_gc = NULL;
-
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+  /* zero-out the scrollbars */
+  if (clist->vadjustment)
+    {
+      gtk_adjustment_set_value (clist->vadjustment, 0.0);
+      CLIST_REFRESH (clist);
+    }
+  else
+    gtk_widget_queue_resize (GTK_WIDGET (clist));
 }
 
 static void
-gtk_clist_map (GtkWidget * widget)
+real_row_move (GtkCList *clist,
+              gint      source_row,
+              gint      dest_row)
 {
-  gint i;
-  GtkCList *clist;
+  GtkCListRow *clist_row;
+  GList *list;
+  gint first, last;
+  gint d;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist = GTK_CLIST (widget);
+  if (GTK_CLIST_AUTO_SORT(clist))
+    return;
 
-  if (!GTK_WIDGET_MAPPED (widget))
-    {
-      GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+  if (source_row < 0 || source_row >= clist->rows ||
+      dest_row   < 0 || dest_row   >= clist->rows ||
+      source_row == dest_row)
+    return;
 
-      gdk_window_show (widget->window);
-      gdk_window_show (clist->title_window);
-      gdk_window_show (clist->clist_window);
+  gtk_clist_freeze (clist);
 
-      /* map column buttons */
-      for (i = 0; i < clist->columns; i++)
-       if (clist->column[i].button &&
-           GTK_WIDGET_VISIBLE (clist->column[i].button) &&
-           !GTK_WIDGET_MAPPED (clist->column[i].button))
-         gtk_widget_map (clist->column[i].button);
-      
-      /* map resize windows AFTER column buttons (above) */
-      for (i = 0; i < clist->columns; i++)
-       if (clist->column[i].window && clist->column[i].button)
-         gdk_window_show (clist->column[i].window);
-       
-      /* map vscrollbars */
-      if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
-         !GTK_WIDGET_MAPPED (clist->vscrollbar))
-       gtk_widget_map (clist->vscrollbar);
+  /* unlink source row */
+  clist_row = ROW_ELEMENT (clist, source_row)->data;
+  if (source_row == clist->rows - 1)
+    clist->row_list_end = clist->row_list_end->prev;
+  clist->row_list = g_list_remove (clist->row_list, clist_row);
+  clist->rows--;
 
-      if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
-         !GTK_WIDGET_MAPPED (clist->hscrollbar))
-       gtk_widget_map (clist->hscrollbar);
+  /* relink source row */
+  clist->row_list = g_list_insert (clist->row_list, clist_row, dest_row);
+  if (dest_row == clist->rows)
+    clist->row_list_end = clist->row_list_end->next;
+  clist->rows++;
 
-      /* unfreeze the list */
-      GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
+  /* sync selection */
+  if (source_row > dest_row)
+    {
+      first = dest_row;
+      last  = source_row;
+      d = 1;
+    }
+  else
+    {
+      first = source_row;
+      last  = dest_row;
+      d = -1;
     }
-}
 
-static void
-gtk_clist_unmap (GtkWidget * widget)
+  for (list = clist->selection; list; list = list->next)
+    {
+      if (list->data == GINT_TO_POINTER (source_row))
+       list->data = GINT_TO_POINTER (dest_row);
+      else if (first <= GPOINTER_TO_INT (list->data) &&
+              last >= GPOINTER_TO_INT (list->data))
+       list->data = GINT_TO_POINTER (GPOINTER_TO_INT (list->data) + d);
+    }
+  
+  if (clist->focus_row == source_row)
+    clist->focus_row = dest_row;
+  else if (clist->focus_row > first)
+    clist->focus_row += d;
+
+  gtk_clist_thaw (clist);
+}
+
+/* PUBLIC ROW FUNCTIONS
+ *   gtk_clist_moveto
+ *   gtk_clist_set_row_height
+ *   gtk_clist_set_row_data
+ *   gtk_clist_set_row_data_full
+ *   gtk_clist_get_row_data
+ *   gtk_clist_find_row_from_data
+ *   gtk_clist_swap_rows
+ *   gtk_clist_row_move
+ *   gtk_clist_row_is_visible
+ *   gtk_clist_set_foreground
+ *   gtk_clist_set_background
+ */
+void
+gtk_clist_moveto (GtkCList *clist,
+                 gint      row,
+                 gint      column,
+                 gfloat    row_align,
+                 gfloat    col_align)
 {
-  gint i;
-  GtkCList *clist;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (widget));
+  if (row < -1 || row >= clist->rows)
+    return;
+  if (column < -1 || column >= clist->columns)
+    return;
 
-  clist = GTK_CLIST (widget);
+  row_align = CLAMP (row_align, 0, 1);
+  col_align = CLAMP (col_align, 0, 1);
 
-  if (GTK_WIDGET_MAPPED (widget))
+  /* adjust horizontal scrollbar */
+  if (clist->hadjustment && column >= 0)
     {
-      GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+      gint x;
 
-      for (i = 0; i < clist->columns; i++)
-       if (clist->column[i].window)
-         gdk_window_hide (clist->column[i].window);
-
-      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 (clist->column[i].button &&
-           GTK_WIDGET_MAPPED (clist->column[i].button))
-         gtk_widget_unmap (clist->column[i].button);
-
-      /* freeze the list */
-      GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
+      x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
+          (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
+                        CELL_SPACING - clist->column[column].area.width)));
+      if (x < 0)
+       gtk_adjustment_set_value (clist->hadjustment, 0.0);
+      else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
+       gtk_adjustment_set_value 
+         (clist->hadjustment, LIST_WIDTH (clist) - clist->clist_window_width);
+      else
+       gtk_adjustment_set_value (clist->hadjustment, x);
     }
+
+  /* adjust vertical scrollbar */
+  if (clist->vadjustment && row >= 0)
+    move_vertical (clist, row, row_align);
 }
 
-static void
-gtk_clist_draw (GtkWidget * widget,
-               GdkRectangle * area)
+void
+gtk_clist_set_row_height (GtkCList *clist,
+                         guint     height)
 {
-  GtkCList *clist;
-  gint border_width;
-  GdkRectangle child_area;
-  int i;
-
-  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);
-      border_width = GTK_CONTAINER (widget)->border_width;
-
-      gdk_window_clear_area (widget->window,
-                            area->x - border_width, 
-                            area->y - border_width,
-                            area->width, area->height);
+  GtkWidget *widget;
 
-      /* draw list shadow/border */
-      gtk_draw_shadow (widget->style, widget->window,
-                      GTK_STATE_NORMAL, clist->shadow_type,
-                      0, 0, 
-                      clist->clist_window_width + (2 * widget->style->klass->xthickness),
-                      clist->clist_window_height + (2 * widget->style->klass->ythickness) +
-                      clist->column_title_area.height);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-      gdk_window_clear_area (clist->clist_window,
-                            0, 0, -1, -1);
+  widget = GTK_WIDGET (clist);
 
-      draw_rows (clist, NULL);
+  if (height > 0)
+    {
+      clist->row_height = height;
+      GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
+    }
+  else
+    {
+      GTK_CLIST_UNSET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
+      clist->row_height = 0;
+    }
 
-      for (i = 0; i < clist->columns; i++)
+  if (GTK_WIDGET_REALIZED (clist))
+    {
+      if (!GTK_CLIST_ROW_HEIGHT_SET(clist))
        {
-         if (!clist->column[i].visible)
-           continue;
-         if (gtk_widget_intersect (clist->column[i].button, area, &child_area))
-           gtk_widget_draw (clist->column[i].button, &child_area);
+         clist->row_height = (widget->style->font->ascent +
+                              widget->style->font->descent + 1);
+         clist->row_center_offset = widget->style->font->ascent + 1.5;
        }
+      else
+       clist->row_center_offset = 1.5 + (clist->row_height +
+                                         widget->style->font->ascent -
+                                         widget->style->font->descent - 1) / 2;
     }
+      
+  CLIST_REFRESH (clist);
 }
 
-static gint
-gtk_clist_expose (GtkWidget * widget,
-                 GdkEventExpose * event)
+void
+gtk_clist_set_row_data (GtkCList *clist,
+                       gint      row,
+                       gpointer  data)
 {
-  GtkCList *clist;
+  gtk_clist_set_row_data_full (clist, row, data, NULL);
+}
 
-  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);
+void
+gtk_clist_set_row_data_full (GtkCList         *clist,
+                            gint              row,
+                            gpointer          data,
+                            GtkDestroyNotify  destroy)
+{
+  GtkCListRow *clist_row;
 
-  if (GTK_WIDGET_DRAWABLE (widget))
-    {
-      clist = GTK_CLIST (widget);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-      /* draw border */
-      if (event->window == widget->window)
-       gtk_draw_shadow (widget->style, widget->window,
-                        GTK_STATE_NORMAL, clist->shadow_type,
-                        0, 0,
-                        clist->clist_window_width + (2 * widget->style->klass->xthickness),
-                        clist->clist_window_height + (2 * widget->style->klass->ythickness) +
-                        clist->column_title_area.height);
+  if (row < 0 || row > (clist->rows - 1))
+    return;
 
-      /* exposure events on the list */
-      if (event->window == clist->clist_window)
-       draw_rows (clist, &event->area);
-    }
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  return FALSE;
+  if (clist_row->destroy)
+    clist_row->destroy (clist_row->data);
+  
+  clist_row->data = data;
+  clist_row->destroy = destroy;
 }
 
-static gint
-gtk_clist_button_press (GtkWidget * widget,
-                       GdkEventButton * event)
+gpointer
+gtk_clist_get_row_data (GtkCList *clist,
+                       gint      row)
 {
-  gint i;
-  GtkCList *clist;
-  gint x;
-  gint y;
-  gint row;
-  gint 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);
-
-  /* we don't handle button 2 and 3 */
-  if (event->button != 1)
-    return FALSE;
-  
-  /* selections on the list */
-  if (event->window == clist->clist_window)
-    {
-      x = event->x;
-      y = event->y;
+  GtkCListRow *clist_row;
 
-      if (get_selection_info (clist, x, y, &row, &column))
-       {
-         gint old_row = clist->focus_row;
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
 
-         if (clist->focus_row == -1)
-           old_row = row;
+  if (row < 0 || row > (clist->rows - 1))
+    return NULL;
 
-         if (event->type == GDK_BUTTON_PRESS)
-           {
-             GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
-             gdk_pointer_grab (clist->clist_window, FALSE,
-                               GDK_POINTER_MOTION_HINT_MASK |
-                               GDK_BUTTON1_MOTION_MASK |
-                               GDK_BUTTON_RELEASE_MASK,
-                               NULL, NULL, event->time);
-             gtk_grab_add (widget);
-           }
-         else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
-           {
-             GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
-             gtk_grab_remove (widget);
-             gdk_pointer_ungrab (event->time);
-           }
+  clist_row = ROW_ELEMENT (clist, row)->data;
+  return clist_row->data;
+}
 
-         if (GTK_CLIST_ADD_MODE (clist))
-           {
-             GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
-             if (GTK_WIDGET_HAS_FOCUS (widget))
-               {
-                 gtk_clist_draw_focus (widget);
-                 gdk_gc_set_line_attributes (clist->xor_gc, 1,
-                                             GDK_LINE_SOLID, 0, 0);
-                 clist->focus_row = row;
-                 gtk_clist_draw_focus (widget);
-               }
-             else
-               {
-                 gdk_gc_set_line_attributes (clist->xor_gc, 1,
-                                             GDK_LINE_SOLID, 0, 0);
-                 clist->focus_row = row;
-               }
-           }
-         else if (row != clist->focus_row)
-           {
-             if (GTK_WIDGET_HAS_FOCUS (widget))
-               {
-                 gtk_clist_draw_focus (widget);
-                 clist->focus_row = row;
-                 gtk_clist_draw_focus (widget);
-               }
-             else
-               clist->focus_row = row;
-           }
+gint
+gtk_clist_find_row_from_data (GtkCList *clist,
+                             gpointer  data)
+{
+  GList *list;
+  gint n;
 
-         if (!GTK_WIDGET_HAS_FOCUS (widget))
-           gtk_widget_grab_focus (widget);
+  g_return_val_if_fail (clist != NULL, -1);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
 
-         switch (clist->selection_mode)
-           {
-           case GTK_SELECTION_SINGLE:
-           case GTK_SELECTION_MULTIPLE:
-             if (event->type != GDK_BUTTON_PRESS)
-               select_row (clist, row, column, (GdkEvent *) event);
-             else
-               clist->anchor = row;
-             break;
+  for (n = 0, list = clist->row_list; list; n++, list = list->next)
+    if (GTK_CLIST_ROW (list)->data == data)
+      return n;
 
-           case GTK_SELECTION_BROWSE:
-             select_row (clist, row, column, (GdkEvent *) event);
-             break;
+  return -1;
+}
 
-           case GTK_SELECTION_EXTENDED:
-             if (event->type != GDK_BUTTON_PRESS)
-               {
-                 if (clist->anchor != -1)
-                   {
-                     update_extended_selection (clist, clist->focus_row);
-                     GTK_CLIST_CLASS_FW (clist)->resync_selection
-                       (clist, (GdkEvent *) event);
-                   }
-                 select_row (clist, row, column, (GdkEvent *) event);
-                 break;
-               }
-             
-             if (event->state & GDK_CONTROL_MASK)
-               {
-                 if (event->state & GDK_SHIFT_MASK)
-                   {
-                     if (clist->anchor < 0)
-                       {
-                         g_list_free (clist->undo_selection);
-                         g_list_free (clist->undo_unselection);
-                         clist->undo_selection = NULL;
-                         clist->undo_unselection = NULL;
-                         clist->anchor = old_row;
-                         clist->drag_pos = old_row;
-                         clist->undo_anchor = old_row;
-                       }
-                     update_extended_selection (clist, clist->focus_row);
-                   }
-                 else
-                   {
-                     if (clist->anchor == -1)
-                       set_anchor (clist, TRUE, row, old_row);
-                     else
-                       update_extended_selection (clist, clist->focus_row);
-                   }
-                 break;
-               }
+void 
+gtk_clist_swap_rows (GtkCList *clist,
+                    gint      row1, 
+                    gint      row2)
+{
+  gint first, last;
 
-             if (event->state & GDK_SHIFT_MASK)
-               {
-                 set_anchor (clist, FALSE, old_row, old_row);
-                 update_extended_selection (clist, clist->focus_row);
-                 break;
-               }
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  g_return_if_fail (row1 != row2);
 
-             if (clist->anchor == -1)
-               set_anchor (clist, FALSE, row, old_row);
-             else
-               update_extended_selection (clist, clist->focus_row);
-             break;
+  if (GTK_CLIST_AUTO_SORT(clist))
+    return;
 
-           default:
-             break;
-           }
-       }
+  gtk_clist_freeze (clist);
 
-      return FALSE;
-    }
+  first = MIN (row1, row2);
+  last  = MAX (row1, row2);
 
-  /* press on resize windows */
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].resizeable && clist->column[i].window &&
-       event->window == clist->column[i].window)
-      {
-       gdk_pointer_grab (clist->column[i].window, FALSE,
-                         GDK_POINTER_MOTION_HINT_MASK |
-                         GDK_BUTTON1_MOTION_MASK |
-                         GDK_BUTTON_RELEASE_MASK,
-                         NULL, NULL, event->time);
-       gtk_grab_add (widget);
-       GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
+  gtk_clist_row_move (clist, last, first);
+  gtk_clist_row_move (clist, first + 1, last);
+  
+  gtk_clist_thaw (clist);
+}
 
-       if (!GTK_WIDGET_HAS_FOCUS (widget))
-         gtk_widget_grab_focus (widget);
+void
+gtk_clist_row_move (GtkCList *clist,
+                   gint      source_row,
+                   gint      dest_row)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-       clist->drag_pos = i;
-       clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
-                        clist->column[i].area.width + CELL_SPACING);
+  if (GTK_CLIST_AUTO_SORT(clist))
+    return;
 
-       if (GTK_CLIST_ADD_MODE (clist))
-         gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
-       draw_xor_line (clist);
+  if (source_row < 0 || source_row >= clist->rows ||
+      dest_row   < 0 || dest_row   >= clist->rows ||
+      source_row == dest_row)
+    return;
 
-       return FALSE;
-      }
-  return FALSE;
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[ROW_MOVE],
+                  source_row, dest_row);
 }
 
-static gint
-gtk_clist_button_release (GtkWidget * widget,
-                         GdkEventButton * event)
+GtkVisibility
+gtk_clist_row_is_visible (GtkCList *clist,
+                         gint      row)
 {
-  GtkCList *clist;
+  gint top;
 
-  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);
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
 
-  clist = GTK_CLIST (widget);
+  if (row < 0 || row >= clist->rows)
+    return GTK_VISIBILITY_NONE;
 
-  /* we don't handle button 2 and 3 */
-  if (event->button != 1)
-    return FALSE;
+  if (clist->row_height == 0)
+    return GTK_VISIBILITY_NONE;
 
-  /* release on resize windows */
-  if (GTK_CLIST_IN_DRAG (clist))
-    {
-      gint width;
-      gint x;
-      gint i;
+  if (row < ROW_FROM_YPIXEL (clist, 0))
+    return GTK_VISIBILITY_NONE;
 
-      i = clist->drag_pos;
-      clist->drag_pos = -1;
+  if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
+    return GTK_VISIBILITY_NONE;
 
-      GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
-      gtk_widget_get_pointer (widget, &x, NULL);
-      gtk_grab_remove (widget);
-      gdk_pointer_ungrab (event->time);
+  top = ROW_TOP_YPIXEL (clist, row);
 
-      if (clist->x_drag >= 0)
-       draw_xor_line (clist);
+  if ((top < 0)
+      || ((top + clist->row_height) >= clist->clist_window_height))
+    return GTK_VISIBILITY_PARTIAL;
 
-      if (GTK_CLIST_ADD_MODE (clist))
-       {
-         gdk_gc_set_line_attributes (clist->xor_gc, 1,
-                                     GDK_LINE_ON_OFF_DASH, 0, 0);
-         gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
-       }
+  return GTK_VISIBILITY_FULL;
+}
 
-      width = new_column_width (clist, i, &x);
-      resize_column (clist, i, width);
-      return FALSE;
-    }
+void
+gtk_clist_set_foreground (GtkCList *clist,
+                         gint      row,
+                         GdkColor *color)
+{
+  GtkCListRow *clist_row;
 
-  if (GTK_CLIST_DRAG_SELECTION (clist))
-    {
-      gint row;
-      gint column;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-      GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
-      gtk_grab_remove (widget);
-      gdk_pointer_ungrab (event->time);
-      if (clist->htimer)
-       {
-         gtk_timeout_remove (clist->htimer);
-         clist->htimer = 0;
-       }
-      if (clist->vtimer)
-       {
-         gtk_timeout_remove (clist->vtimer);
-         clist->vtimer = 0;
-       }
-      switch (clist->selection_mode)
-       {
-       case GTK_SELECTION_EXTENDED:
-         if (!(event->state & GDK_SHIFT_MASK) ||
-             event->x < 0 || event->x >= clist->clist_window_width ||
-             event->y < 0 || event->y >= clist->clist_window_height)
-           GTK_CLIST_CLASS_FW (clist)->resync_selection
-             (clist, (GdkEvent *) event);
-         break;
+  if (row < 0 || row >= clist->rows)
+    return;
 
-       case GTK_SELECTION_SINGLE:
-       case GTK_SELECTION_MULTIPLE:
-         if (get_selection_info (clist, event->x, event->y, &row, &column))
-           {
-             if (clist->anchor == clist->focus_row)
-               toggle_row (clist, row, column, (GdkEvent *) event);
-           }
-         clist->anchor = -1;
-         break;
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-       default:
-         break;
-       }
+  if (color)
+    {
+      clist_row->foreground = *color;
+      clist_row->fg_set = TRUE;
+      if (GTK_WIDGET_REALIZED (clist))
+       gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)),
+                        &clist_row->foreground);
     }
+  else
+    clist_row->fg_set = FALSE;
 
-  return FALSE;
+  if (CLIST_UNFROZEN (clist) && gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
 }
 
-static gint
-horizontal_timeout (GtkCList *clist)
+void
+gtk_clist_set_background (GtkCList *clist,
+                         gint      row,
+                         GdkColor *color)
 {
-  gint x, y;
-  GdkEventMotion event;
-  GdkModifierType mask;
+  GtkCListRow *clist_row;
 
-  g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist->htimer = 0;
-  gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
+  if (row < 0 || row >= clist->rows)
+    return;
 
-  event.is_hint = 0;
-  event.x = x;
-  event.y = y;
-  event.state = mask;
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  gtk_clist_motion (GTK_WIDGET (clist), &event);
+  if (color)
+    {
+      clist_row->background = *color;
+      clist_row->bg_set = TRUE;
+      if (GTK_WIDGET_REALIZED (clist))
+       gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)),
+                        &clist_row->background);
+    }
+  else
+    clist_row->bg_set = FALSE;
 
-  return FALSE;
+  if (CLIST_UNFROZEN (clist)
+      && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
+    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
 }
 
-static gint
-vertical_timeout (GtkCList *clist)
+/* PUBLIC ROW/CELL STYLE FUNCTIONS
+ *   gtk_clist_set_cell_style
+ *   gtk_clist_get_cell_style
+ *   gtk_clist_set_row_style
+ *   gtk_clist_get_row_style
+ */
+void
+gtk_clist_set_cell_style (GtkCList *clist,
+                         gint      row,
+                         gint      column,
+                         GtkStyle *style)
 {
-  gint x, y;
-  GdkEventMotion event;
-  GdkModifierType mask;
+  GtkRequisition requisition = { 0 };
+  GtkCListRow *clist_row;
 
-  g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist->vtimer = 0;
-  gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < 0 || column >= clist->columns)
+    return;
 
-  event.is_hint = 0;
-  event.x = x;
-  event.y = y;
-  event.state = mask;
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  gtk_clist_motion (GTK_WIDGET (clist), &event);
+  if (clist_row->cell[column].style == style)
+    return;
 
-  return FALSE;
-}
+  if (clist->column[column].auto_resize &&
+      !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
+                                                  column, &requisition);
 
-static void
-move_vertical (GtkCList *clist,
-              gint row,
-              gfloat align)
-{
-  gint y;
-  GtkAdjustment *adj;
+  if (clist_row->cell[column].style)
+    {
+      if (GTK_WIDGET_REALIZED (clist))
+        gtk_style_detach (clist_row->cell[column].style);
+      gtk_style_unref (clist_row->cell[column].style);
+    }
 
-  adj = GTK_RANGE (clist->vscrollbar)->adjustment;
+  clist_row->cell[column].style = style;
 
-  y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
-  
-  y = y - align * (clist->clist_window_height - clist->row_height)
-    + (2 * align - 1) * CELL_SPACING;
-  
-  if (y + adj->page_size > adj->upper)
-    adj->value = adj->upper - adj->page_size;
-  else
-    adj->value = y;
+  if (clist_row->cell[column].style)
+    {
+      gtk_style_ref (clist_row->cell[column].style);
+      
+      if (GTK_WIDGET_REALIZED (clist))
+        clist_row->cell[column].style =
+         gtk_style_attach (clist_row->cell[column].style,
+                           clist->clist_window);
+    }
+
+  column_auto_resize (clist, clist_row, column, requisition.width);
 
-  gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
+  /* redraw the list if it's not frozen */
+  if (CLIST_UNFROZEN (clist))
+    {
+      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+    }
 }
 
-static void
-move_horizontal (GtkCList *clist,
-                gint diff)
+GtkStyle *
+gtk_clist_get_cell_style (GtkCList *clist,
+                         gint      row,
+                         gint      column)
 {
-  gfloat upper;
-  GtkAdjustment *adj;
+  GtkCListRow *clist_row;
 
-  adj = GTK_RANGE (clist->hscrollbar)->adjustment;
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
 
-  adj->value += diff;
+  if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns)
+    return NULL;
 
-  upper = adj->upper - adj->page_size;
-  adj->value = MIN (adj->value, upper);
-  adj->value = MAX (adj->value, 0.0);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
+  return clist_row->cell[column].style;
 }
 
-static gint
-gtk_clist_motion (GtkWidget * widget,
-                 GdkEventMotion * event)
+void
+gtk_clist_set_row_style (GtkCList *clist,
+                        gint      row,
+                        GtkStyle *style)
 {
-  GtkCList *clist;
-  gint x;
-  gint y;
-  gint row;
-  gint new_width;
+  GtkRequisition requisition;
+  GtkCListRow *clist_row;
+  gint *old_width;
+  gint i;
 
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist = GTK_CLIST (widget);
-  if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
-    return FALSE;
+  if (row < 0 || row >= clist->rows)
+    return;
 
-  if (GTK_CLIST_IN_DRAG (clist))
-    {
-      if (event->is_hint || event->window != widget->window)
-       gtk_widget_get_pointer (widget, &x, NULL);
-      else
-       x = event->x;
-      
-      new_width = new_column_width (clist, clist->drag_pos, &x);
-      if (x != clist->x_drag)
-       {
-         /* x_drag < 0 indicates that the xor line is already invisible */
-         if (clist->x_drag >= 0)
-           draw_xor_line (clist);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-         clist->x_drag = x;
+  if (clist_row->style == style)
+    return;
 
-         if (clist->x_drag >= 0)
-           draw_xor_line (clist);
-       }
+  old_width = g_new (gint, clist->columns);
 
-      if (new_width <= MAX (COLUMN_MIN_WIDTH + 1,
-                           clist->column[clist->drag_pos].min_width + 1))
-       {
-         if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0)
-           gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
-         return FALSE;
-       }
-      if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH &&
-         new_width >= clist->column[clist->drag_pos].max_width)
-       {
-         if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width >
-             clist->clist_window_width && x < 0)
-           move_horizontal (clist,
-                            COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) +
-                            new_width - clist->clist_window_width +
-                            COLUMN_INSET + CELL_SPACING);
-         return FALSE;
-       }
+  if (!GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    {
+      for (i = 0; i < clist->columns; i++)
+       if (clist->column[i].auto_resize)
+         {
+           GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
+                                                          i, &requisition);
+           old_width[i] = requisition.width;
+         }
     }
 
-  if (event->is_hint || event->window != clist->clist_window)
-    gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
-
-  /* horizontal autoscrolling */
-  if (LIST_WIDTH (clist) > clist->clist_window_width &&
-      (x < 0 || x >= clist->clist_window_width))
+  if (clist_row->style)
     {
-      if (clist->htimer)
-       return FALSE;
+      if (GTK_WIDGET_REALIZED (clist))
+        gtk_style_detach (clist_row->style);
+      gtk_style_unref (clist_row->style);
+    }
 
-      clist->htimer = gtk_timeout_add
-       (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
+  clist_row->style = style;
 
-      if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
-           (x >= clist->clist_window_width &&
-            GTK_RANGE (clist->hscrollbar)->adjustment->value ==
-            LIST_WIDTH (clist) - clist->clist_window_width)))
-       {
-         if (x < 0)
-           move_horizontal (clist, -1 + (x/2));
-         else
-           move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
-       }
+  if (clist_row->style)
+    {
+      gtk_style_ref (clist_row->style);
+      
+      if (GTK_WIDGET_REALIZED (clist))
+        clist_row->style = gtk_style_attach (clist_row->style,
+                                            clist->clist_window);
     }
 
-  if (GTK_CLIST_IN_DRAG (clist))
-    return FALSE;
-
-  /* vertical autoscrolling */
-  row = ROW_FROM_YPIXEL (clist, y);
+  if (GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
+    for (i = 0; i < clist->columns; i++)
+      column_auto_resize (clist, clist_row, i, old_width[i]);
 
-  /* don't scroll on last pixel row if it's a cell spacing */
-  if (y == clist->clist_window_height-1 &&
-      y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
-    return FALSE;
+  g_free (old_width);
 
-  if (LIST_HEIGHT (clist) > clist->clist_window_height &&
-      (y < 0 || y >= clist->clist_window_height))
+  /* redraw the list if it's not frozen */
+  if (CLIST_UNFROZEN (clist))
     {
-      if (clist->vtimer)
-       return FALSE;
-
-      clist->vtimer = gtk_timeout_add (SCROLL_TIME,
-                                      (GtkFunction) vertical_timeout, clist);
-
-      if (GTK_CLIST_DRAG_SELECTION (clist))
-       {
-         if ((y < 0 && clist->focus_row == 0) ||
-             (y >= clist->clist_window_height &&
-              clist->focus_row == clist->rows-1))
-           return FALSE;
-       }
+      if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
     }
+}
 
-  row = CLAMP (row, 0, clist->rows - 1);
+GtkStyle *
+gtk_clist_get_row_style (GtkCList *clist,
+                        gint      row)
+{
+  GtkCListRow *clist_row;
 
-  if (GTK_CLIST_DRAG_SELECTION (clist))
-    {
-      if (row == clist->focus_row)
-       return FALSE;
+  g_return_val_if_fail (clist != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
 
-      gtk_clist_draw_focus (widget);
-      clist->focus_row = row;
-      gtk_clist_draw_focus (widget);
+  if (row < 0 || row >= clist->rows)
+    return NULL;
 
-      switch (clist->selection_mode)
-       {
-       case GTK_SELECTION_BROWSE:
-         select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
-         break;
-         
-       case GTK_SELECTION_EXTENDED:
-         update_extended_selection (clist, clist->focus_row);
-         break;
-         
-       default:
-         break;
-       }
-    }
-  
-  if (ROW_TOP_YPIXEL(clist, row) < 0)
-    move_vertical (clist, row, 0);
-  else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
-          clist->clist_window_height)
-    move_vertical (clist, row, 1);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  return FALSE;
+  return clist_row->style;
 }
 
-static void
-gtk_clist_size_request (GtkWidget * widget,
-                       GtkRequisition * requisition)
+/* PUBLIC SELECTION FUNCTIONS
+ *   gtk_clist_set_selectable
+ *   gtk_clist_get_selectable
+ *   gtk_clist_select_row
+ *   gtk_clist_unselect_row
+ *   gtk_clist_select_all
+ *   gtk_clist_unselect_all
+ *   gtk_clist_undo_selection
+ */
+void
+gtk_clist_set_selectable (GtkCList *clist,
+                         gint      row,
+                         gboolean  selectable)
 {
-  gint i;
-  GtkCList *clist;
+  GtkCListRow *clist_row;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (widget));
-  g_return_if_fail (requisition != NULL);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist = GTK_CLIST (widget);
+  if (row < 0 || row >= clist->rows)
+    return;
 
-  add_style_data (clist);
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-  requisition->width = 0;
-  requisition->height = 0;
+  if (selectable == clist_row->selectable)
+    return;
 
-  /* compute the size of the column title (title) area */
-  clist->column_title_area.height = 0;
-  if (GTK_CLIST_SHOW_TITLES (clist))
-    for (i = 0; i < clist->columns; i++)
-      if (clist->column[i].button)
+  clist_row->selectable = selectable;
+
+  if (!selectable && clist_row->state == GTK_STATE_SELECTED)
+    {
+      if (clist->anchor >= 0 &&
+         clist->selection_mode == GTK_SELECTION_EXTENDED)
        {
-         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);
+         clist->drag_button = 0;
+         remove_grab (clist);
+         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
        }
-  requisition->height += clist->column_title_area.height;
+      gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
+                      row, -1, NULL);
+    }      
+}
 
-  /* 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);
+gboolean
+gtk_clist_get_selectable (GtkCList *clist,
+                         gint      row)
+{
+  g_return_val_if_fail (clist != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
 
-      requisition->width += (clist->vscrollbar->requisition.width +
-                            SCROLLBAR_SPACING (clist));
-      requisition->height = MAX (requisition->height,
-                                clist->vscrollbar->requisition.height);
-    }
+  if (row < 0 || row >= clist->rows)
+    return FALSE;
 
-  /* 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);
+  return GTK_CLIST_ROW (ROW_ELEMENT (clist, row))->selectable;
+}
 
-      requisition->height += (clist->hscrollbar->requisition.height +
-                             SCROLLBAR_SPACING (clist));
-      requisition->width = MAX (clist->hscrollbar->requisition.width, 
-                               requisition->width - 
-                               clist->vscrollbar->requisition.width);
+void
+gtk_clist_select_row (GtkCList *clist,
+                     gint      row,
+                     gint      column)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-    }
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < -1 || column >= clist->columns)
+    return;
 
-  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);
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                  row, column, NULL);
 }
 
-static void
-gtk_clist_size_allocate (GtkWidget * widget,
-                        GtkAllocation * allocation)
+void
+gtk_clist_unselect_row (GtkCList *clist,
+                       gint      row,
+                       gint      column)
 {
-  GtkCList *clist;
-  GtkAllocation clist_allocation;
-  GtkAllocation child_allocation;
-  gint i, vscrollbar_vis, hscrollbar_vis;
-  gint border_width;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (widget));
-  g_return_if_fail (allocation != NULL);
+  if (row < 0 || row >= clist->rows)
+    return;
+  if (column < -1 || column >= clist->columns)
+    return;
 
-  clist = GTK_CLIST (widget);
-  widget->allocation = *allocation;
-  border_width = GTK_CONTAINER (widget)->border_width;
+  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
+                  row, column, NULL);
+}
 
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      gdk_window_move_resize (widget->window,
-                             allocation->x + border_width,
-                             allocation->y + border_width,
-                             allocation->width - border_width * 2,
-                             allocation->height - border_width * 2);
-    }
+void
+gtk_clist_select_all (GtkCList *clist)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  /* use internal allocation structure for all the math
-   * because it's easier than always subtracting the container
-   * border width */
-  clist->internal_allocation.x = 0;
-  clist->internal_allocation.y = 0;
-  clist->internal_allocation.width = MAX (1, allocation->width -
-                                         border_width * 2);
-  clist->internal_allocation.height = MAX (1, allocation->height -
-                                          border_width * 2);
-       
-  /* allocate clist window assuming no scrollbars */
-  clist_allocation.x = (clist->internal_allocation.x +
-                       widget->style->klass->xthickness);
-  clist_allocation.y = (clist->internal_allocation.y +
-                       widget->style->klass->ythickness +
-                       clist->column_title_area.height);
-  clist_allocation.width = MAX (1, clist->internal_allocation.width - 
-                               (2 * widget->style->klass->xthickness));
-  clist_allocation.height = MAX (1, clist->internal_allocation.height -
-                                (2 * widget->style->klass->ythickness) -
-                                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 = MAX (1, clist_allocation.width - 
-                                       (clist->vscrollbar->requisition.width +
-                                        SCROLLBAR_SPACING (clist)));
-       }  
-      
-      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 = MAX (1, clist_allocation.height - 
-                                        (clist->hscrollbar->requisition.height
-                                         + SCROLLBAR_SPACING (clist)));
-       }  
-    }
-  
-  clist->clist_window_width = clist_allocation.width;
-  clist->clist_window_height = clist_allocation.height;
-  
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      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 = widget->style->klass->xthickness;
-  clist->column_title_area.y = widget->style->klass->ythickness;
-  clist->column_title_area.width = clist_allocation.width;
-  
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      gdk_window_move_resize (clist->title_window,
-                             clist->column_title_area.x,
-                             clist->column_title_area.y,
-                             clist->column_title_area.width,
-                             clist->column_title_area.height);
-    }
-  
-  /* column button allocation */
-  size_allocate_columns (clist);
-  size_allocate_title_buttons (clist);
+  GTK_CLIST_CLASS_FW (clist)->select_all (clist);
+}
 
-  adjust_scrollbars (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 = MAX (1, clist->internal_allocation.height -
-                                    (hscrollbar_vis ?
-                                     (clist->hscrollbar->requisition.height +
-                                      SCROLLBAR_SPACING (clist)) : 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 = MAX (1, clist->internal_allocation.width -
-                                   (vscrollbar_vis ?
-                                    (clist->vscrollbar->requisition.width +
-                                     SCROLLBAR_SPACING (clist)) : 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);
-    }
+void
+gtk_clist_unselect_all (GtkCList *clist)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  /* set the vscrollbar adjustments */
-  adjust_scrollbars (clist);
+  GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
 }
 
-/* 
- * GTKCONTAINER
- *   gtk_clist_forall
+void
+gtk_clist_undo_selection (GtkCList *clist)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
+      (clist->undo_selection || clist->undo_unselection))
+    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
+}
+
+/* PRIVATE SELECTION FUNCTIONS
+ *   selection_find
+ *   toggle_row
+ *   fake_toggle_row
+ *   toggle_focus_row
+ *   toggle_add_mode
+ *   real_select_row
+ *   real_unselect_row
+ *   real_select_all
+ *   real_unselect_all
+ *   fake_unselect_all
+ *   real_undo_selection
+ *   set_anchor
+ *   resync_selection
+ *   update_extended_selection
+ *   start_selection
+ *   end_selection
+ *   extend_selection
+ *   sync_selection
  */
-static void
-gtk_clist_forall (GtkContainer *container,
-                 gboolean      include_internals,
-                 GtkCallback   callback,
-                 gpointer      callback_data)
+static GList *
+selection_find (GtkCList *clist,
+               gint      row_number,
+               GList    *row_list_element)
 {
-  GtkCList *clist;
+  return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
+}
 
-  g_return_if_fail (container != NULL);
-  g_return_if_fail (GTK_IS_CLIST (container));
-  g_return_if_fail (callback != NULL);
+static void
+toggle_row (GtkCList *clist,
+           gint      row,
+           gint      column,
+           GdkEvent *event)
+{
+  GtkCListRow *clist_row;
 
-  clist = GTK_CLIST (container);
-      
-  if (include_internals)
+  switch (clist->selection_mode)
     {
-      guint i;
-      
-      /* callback for the column buttons */
-      for (i = 0; i < clist->columns; i++)
-       if (clist->column[i].button)
-         (*callback) (clist->column[i].button, callback_data);
-      
-      /* callbacks for the scrollbars */
-      if (clist->vscrollbar)
-       (*callback) (clist->vscrollbar, callback_data);
-      if (clist->hscrollbar)
-       (*callback) (clist->hscrollbar, callback_data);
+    case GTK_SELECTION_EXTENDED:
+    case GTK_SELECTION_MULTIPLE:
+    case GTK_SELECTION_SINGLE:
+      clist_row = ROW_ELEMENT (clist, row)->data;
+
+      if (!clist_row)
+       return;
+
+      if (clist_row->state == GTK_STATE_SELECTED)
+       {
+         gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
+                          row, column, event);
+         return;
+       }
+    case GTK_SELECTION_BROWSE:
+      gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                      row, column, event);
+      break;
     }
 }
 
-/*
- * DRAWING
- *   draw_row
- *   draw_rows
- */
 static void
-draw_row (GtkCList * clist,
-         GdkRectangle * area,
-         gint row,
-         GtkCListRow * clist_row)
+fake_toggle_row (GtkCList *clist,
+                gint      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;
+  GList *work;
 
-  g_return_if_fail (clist != NULL);
+  work = ROW_ELEMENT (clist, row);
 
-  /* bail now if we arn't drawable yet */
-  if (!GTK_WIDGET_DRAWABLE (clist))
+  if (!work || !GTK_CLIST_ROW (work)->selectable)
     return;
+  
+  if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
+    clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
+  else
+    clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
+  
+  if (CLIST_UNFROZEN (clist) &&
+      gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
+                                         GTK_CLIST_ROW (work));
+}
 
-  if (row < 0 || row >= clist->rows)
+static void
+toggle_focus_row (GtkCList *clist)
+{
+  g_return_if_fail (clist != 0);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
+      clist->focus_row < 0 || clist->focus_row >= clist->rows)
     return;
 
-  widget = GTK_WIDGET (clist);
+  switch (clist->selection_mode)
+    {
+    case  GTK_SELECTION_SINGLE:
+    case  GTK_SELECTION_MULTIPLE:
+      toggle_row (clist, clist->focus_row, 0, NULL);
+      break;
+    case GTK_SELECTION_EXTENDED:
+      g_list_free (clist->undo_selection);
+      g_list_free (clist->undo_unselection);
+      clist->undo_selection = NULL;
+      clist->undo_unselection = NULL;
 
-  /* 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;
+      clist->anchor = clist->focus_row;
+      clist->drag_pos = clist->focus_row;
+      clist->undo_anchor = clist->focus_row;
+      
+      if (GTK_CLIST_ADD_MODE(clist))
+       fake_toggle_row (clist, clist->focus_row);
+      else
+       GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
 
-  /* 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;
+      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+      break;
+    default:
+      break;
+    }
+}
 
-  /* 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;
+static void
+toggle_add_mode (GtkCList *clist)
+{
+  g_return_if_fail (clist != 0);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  
+  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
+      clist->selection_mode != GTK_SELECTION_EXTENDED)
+    return;
 
-  /* select GC for background rectangle */
-  if (clist_row->state == GTK_STATE_SELECTED)
+  gtk_clist_draw_focus (GTK_WIDGET (clist));
+  if (!GTK_CLIST_ADD_MODE(clist))
     {
-      fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
-      bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
+      GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
+      gdk_gc_set_line_attributes (clist->xor_gc, 1,
+                                 GDK_LINE_ON_OFF_DASH, 0, 0);
+      gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
     }
   else
     {
-      if (clist_row->fg_set)
-       {
-         gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
-         fg_gc = clist->fg_gc;
-       }
-      else
-       fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
-       
-      if (clist_row->bg_set)
-       {
-         gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
-         bg_gc = clist->bg_gc;
-       }
-      else
-       bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
+      GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
+      gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
+      clist->anchor_state = GTK_STATE_SELECTED;
     }
+  gtk_clist_draw_focus (GTK_WIDGET (clist));
+}
 
-  /* draw the cell borders and background */
-  if (area)
+static void
+real_select_row (GtkCList *clist,
+                gint      row,
+                gint      column,
+                GdkEvent *event)
+{
+  GtkCListRow *clist_row;
+  GList *list;
+  gint sel_row;
+  gboolean row_selected;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (row < 0 || row > (clist->rows - 1))
+    return;
+
+  switch (clist->selection_mode)
     {
-      if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
-       gdk_draw_rectangle (clist->clist_window,
-                           widget->style->base_gc[GTK_STATE_NORMAL],
-                           TRUE,
-                           intersect_rectangle.x,
-                           intersect_rectangle.y,
-                           intersect_rectangle.width,
-                           intersect_rectangle.height);
+    case GTK_SELECTION_SINGLE:
+    case GTK_SELECTION_BROWSE:
 
-      /* the last row has to clear it's bottom cell spacing too */
-      if (clist_row == clist->row_list_end->data)
+      row_selected = FALSE;
+      list = clist->selection;
+
+      while (list)
        {
-         cell_rectangle.y += clist->row_height + CELL_SPACING;
+         sel_row = GPOINTER_TO_INT (list->data);
+         list = list->next;
 
-         if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
-           gdk_draw_rectangle (clist->clist_window,
-                               widget->style->base_gc[GTK_STATE_NORMAL],
-                               TRUE,
-                               intersect_rectangle.x,
-                               intersect_rectangle.y,
-                               intersect_rectangle.width,
-                               intersect_rectangle.height);
+         if (row == sel_row)
+           row_selected = TRUE;
+         else
+           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 
+                            sel_row, column, event);
        }
 
-      if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
+      if (row_selected)
        return;
-
-      if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
-       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,
-                              intersect_rectangle.x,
-                              intersect_rectangle.y,
-                              intersect_rectangle.width,
-                              intersect_rectangle.height);
+      
+    default:
+      break;
     }
-  else
-    {
-      gdk_draw_rectangle (clist->clist_window,
-                         widget->style->base_gc[GTK_STATE_NORMAL],
-                         TRUE,
-                         cell_rectangle.x,
-                         cell_rectangle.y,
-                         cell_rectangle.width,
-                         cell_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;
 
-         gdk_draw_rectangle (clist->clist_window,
-                             widget->style->base_gc[GTK_STATE_NORMAL],
-                             TRUE,
-                             cell_rectangle.x,
-                             cell_rectangle.y,
-                             cell_rectangle.width,
-                             cell_rectangle.height);     
-       }         
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-      if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
-       gdk_draw_rectangle (clist->clist_window,
-                           bg_gc,
-                           TRUE,
-                           row_rectangle.x,
-                           row_rectangle.y,
-                           row_rectangle.width,
-                           row_rectangle.height);
-      else
-       gdk_window_clear_area (clist->clist_window,
-                              row_rectangle.x,
-                              row_rectangle.y,
-                              row_rectangle.width,
-                              row_rectangle.height);
-    }
+  if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
+    return;
 
-  /* iterate and draw all the columns (row cells) and draw their contents */
-  for (i = 0; i < clist->columns; i++)
+  clist_row->state = GTK_STATE_SELECTED;
+  if (!clist->selection)
     {
-      if (!clist->column[i].visible)
-       continue;
-
-      clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
-      clip_rectangle.width = clist->column[i].area.width;
+      clist->selection = g_list_append (clist->selection,
+                                       GINT_TO_POINTER (row));
+      clist->selection_end = clist->selection;
+    }
+  else
+    clist->selection_end = 
+      g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
+  
+  if (CLIST_UNFROZEN (clist)
+      && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
+    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+}
 
-      /* calculate clipping region clipping region */
-      if (!area)
-       {
-         rect = &clip_rectangle;
-       }
-      else
-       {
-         if (!gdk_rectangle_intersect (area, &clip_rectangle, 
-                                       &intersect_rectangle))
-           continue;
-         rect = &intersect_rectangle;
-       }
+static void
+real_unselect_row (GtkCList *clist,
+                  gint      row,
+                  gint      column,
+                  GdkEvent *event)
+{
+  GtkCListRow *clist_row;
 
-      /* calculate real width for column justification */
-      switch (clist_row->cell[i].type)
-       {
-       case GTK_CELL_EMPTY:
-         continue;
-         break;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-       case GTK_CELL_TEXT:
-         width = gdk_string_width (GTK_WIDGET (clist)->style->font,
-                                   GTK_CELL_TEXT (clist_row->cell[i])->text);
-         break;
+  if (row < 0 || row > (clist->rows - 1))
+    return;
 
-       case GTK_CELL_PIXMAP:
-         gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
-         pixmap_width = width;
-         break;
+  clist_row = ROW_ELEMENT (clist, row)->data;
 
-       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;
+  if (clist_row->state == GTK_STATE_SELECTED)
+    {
+      clist_row->state = GTK_STATE_NORMAL;
 
-       case GTK_CELL_WIDGET:
-         /* unimplimented */
-         continue;
-         break;
+      if (clist->selection_end && 
+         clist->selection_end->data == GINT_TO_POINTER (row))
+       clist->selection_end = clist->selection_end->prev;
 
-       default:
-         continue;
-         break;
-       }
+      clist->selection = g_list_remove (clist->selection,
+                                       GINT_TO_POINTER (row));
+      
+      if (CLIST_UNFROZEN (clist)
+         && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+    }
+}
 
-      switch (clist->column[i].justification)
-       {
-       case GTK_JUSTIFY_LEFT:
-         offset = clip_rectangle.x;
-         break;
+static void
+real_select_all (GtkCList *clist)
+{
+  GList *list;
+  gint i;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-       case GTK_JUSTIFY_RIGHT:
-         offset = (clip_rectangle.x + clip_rectangle.width) - width;
-         break;
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
+    return;
 
-       case GTK_JUSTIFY_CENTER:
-         offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
-         break;
+  switch (clist->selection_mode)
+    {
+    case GTK_SELECTION_SINGLE:
+    case GTK_SELECTION_BROWSE:
+      return;
 
-       case GTK_JUSTIFY_FILL:
-         offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
-         break;
+    case GTK_SELECTION_EXTENDED:
+      g_list_free (clist->undo_selection);
+      g_list_free (clist->undo_unselection);
+      clist->undo_selection = NULL;
+      clist->undo_unselection = NULL;
+         
+      if (clist->rows &&
+         ((GtkCListRow *) (clist->row_list->data))->state !=
+         GTK_STATE_SELECTED)
+       fake_toggle_row (clist, 0);
 
-       default:
-         offset = 0;
-         break;
-       };
+      clist->anchor_state =  GTK_STATE_SELECTED;
+      clist->anchor = 0;
+      clist->drag_pos = 0;
+      clist->undo_anchor = clist->focus_row;
+      update_extended_selection (clist, clist->rows);
+      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+      return;
 
-      /* Draw Text or Pixmap */
-      switch (clist_row->cell[i].type)
+    case GTK_SELECTION_MULTIPLE:
+      for (i = 0, list = clist->row_list; list; i++, list = list->next)
        {
-       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].vertical,
-                          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].vertical;
-
-         if (xdest < clip_rectangle.x)
-           {
-             xsrc = clip_rectangle.x - xdest;
-             pixmap_width -= xsrc;
-             xdest = clip_rectangle.x;
-           }
-
-         if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
-           pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
-
-         if (ydest < clip_rectangle.y)
-           {
-             ysrc = clip_rectangle.y - ydest;
-             height -= ysrc;
-             ydest = clip_rectangle.y;
-           }
-
-         if (ydest + height > clip_rectangle.y + clip_rectangle.height)
-           height = (clip_rectangle.y + clip_rectangle.height) - ydest;
-
-          if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
-          {
-              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);
-
-          if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
-          {
-              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].vertical;
-
-         if (xdest < clip_rectangle.x)
-           {
-             xsrc = clip_rectangle.x - xdest;
-             pixmap_width -= xsrc;
-             xdest = clip_rectangle.x;
-           }
-
-         if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
-           pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
-
-         if (ydest < clip_rectangle.y)
-           {
-             ysrc = clip_rectangle.y - ydest;
-             height -= ysrc;
-             ydest = clip_rectangle.y;
-           }
-
-         if (ydest + height > clip_rectangle.y + clip_rectangle.height)
-           height = (clip_rectangle.y + clip_rectangle.height) - ydest;
-
-          if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
-          {
-              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].vertical,
-                          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;
-       }
-    }
-  if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
-    {
-      if (area)
-       {
-         if (gdk_rectangle_intersect (area, &row_rectangle,
-                                      &intersect_rectangle))
-           {
-             gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
-             gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
-                                 row_rectangle.x, row_rectangle.y,
-                                 row_rectangle.width - 1,
-                                 row_rectangle.height - 1);
-             gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
-           }
+         if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
+           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                            i, -1, NULL);
        }
-      else
-       gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
-                           row_rectangle.x, row_rectangle.y,
-                           row_rectangle.width - 1, row_rectangle.height - 1);
+      return;
     }
 }
 
 static void
-draw_rows (GtkCList * clist,
-          GdkRectangle * area)
+real_unselect_all (GtkCList *clist)
 {
   GList *list;
-  GtkCListRow *clist_row;
-  int i, first_row, last_row;
-
+  gint i;
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (clist->row_height == 0 ||
-      !GTK_WIDGET_DRAWABLE (clist))
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
     return;
 
-  if (area)
-    {
-      first_row = ROW_FROM_YPIXEL (clist, area->y);
-      last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
-    }
-  else
+  switch (clist->selection_mode)
     {
-      first_row = ROW_FROM_YPIXEL (clist, 0);
-      last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
-    }
+    case GTK_SELECTION_BROWSE:
+      if (clist->focus_row >= 0)
+       {
+         gtk_signal_emit (GTK_OBJECT (clist),
+                          clist_signals[SELECT_ROW],
+                          clist->focus_row, -1, NULL);
+         return;
+       }
+      break;
+    case GTK_SELECTION_EXTENDED:
+      g_list_free (clist->undo_selection);
+      g_list_free (clist->undo_unselection);
+      clist->undo_selection = NULL;
+      clist->undo_unselection = NULL;
 
-  /* this is a small special case which exposes the bottom cell line
-   * on the last row -- it might go away if I change the wall the cell spacings
-   * are drawn */
-  if (clist->rows == first_row)
-    first_row--;
+      clist->anchor = -1;
+      clist->drag_pos = -1;
+      clist->undo_anchor = clist->focus_row;
+      break;
+    default:
+      break;
+    }
 
-  list = g_list_nth (clist->row_list, first_row);
-  i = first_row;
+  list = clist->selection;
   while (list)
     {
-      clist_row = list->data;
+      i = GPOINTER_TO_INT (list->data);
       list = list->next;
-
-      if (i > last_row)
-       return;
-
-      GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
-      i++;
+      gtk_signal_emit (GTK_OBJECT (clist),
+                      clist_signals[UNSELECT_ROW], i, -1, NULL);
     }
-
-  if (!area)
-    gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
 }
 
-/*
- * SIZE ALLOCATION
- *   size_allocate_title_buttons
- *   size_allocate_columns
- */
 static void
-size_allocate_title_buttons (GtkCList * clist)
+fake_unselect_all (GtkCList *clist,
+                  gint      row)
 {
-  GtkAllocation button_allocation;
-  gint last_column;
-  gint last_button = 0;
+  GList *list;
+  GList *work;
   gint i;
 
-  if (!GTK_WIDGET_REALIZED (clist))
-    return;
-
-  button_allocation.x = clist->hoffset;
-  button_allocation.y = 0;
-  button_allocation.width = 0;
-  button_allocation.height = clist->column_title_area.height;
-
-  /* find last visible column */
-  for (last_column = clist->columns - 1; last_column >= 0; last_column--)
-    if (clist->column[last_column].visible)
-      break;
-
-  for (i = 0; i < last_column; i++)
+  if (row >= 0 && (work = ROW_ELEMENT (clist, row)))
     {
-      if (!clist->column[i].visible)
-       {
-         last_button = i + 1;
-         gdk_window_hide (clist->column[i].window);
-         continue;
-       }
-
-      button_allocation.width += (clist->column[i].area.width +
-                                 CELL_SPACING + 2 * COLUMN_INSET);
-
-      if (!clist->column[i + 1].button)
-       {
-         gdk_window_hide (clist->column[i].window);
-         continue;
-       }
-
-      gtk_widget_size_allocate (clist->column[last_button].button,
-                               &button_allocation);
-      button_allocation.x += button_allocation.width;
-      button_allocation.width = 0;
-
-      if (clist->column[last_button].resizeable)
+      if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
+         GTK_CLIST_ROW (work)->selectable)
        {
-         gdk_window_show (clist->column[last_button].window);
-         gdk_window_move_resize (clist->column[last_button].window,
-                                 button_allocation.x - (DRAG_WIDTH / 2), 
-                                 0, DRAG_WIDTH,
-                                 clist->column_title_area.height);
-       }
-      else
-       gdk_window_hide (clist->column[last_button].window);
-
-      last_button = i + 1;
+         GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
+         
+         if (CLIST_UNFROZEN (clist) &&
+             gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
+           GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
+                                                 GTK_CLIST_ROW (work));
+       }  
     }
 
-  button_allocation.width += (clist->column[last_column].area.width +
-                             2 * (CELL_SPACING + COLUMN_INSET));
-  gtk_widget_size_allocate (clist->column[last_button].button,
-                           &button_allocation);
+  clist->undo_selection = clist->selection;
+  clist->selection = NULL;
+  clist->selection_end = NULL;
 
-  if (clist->column[last_button].resizeable)
+  for (list = clist->undo_selection; list; list = list->next)
     {
-      button_allocation.x += button_allocation.width;
+      if ((i = GPOINTER_TO_INT (list->data)) == row ||
+         !(work = g_list_nth (clist->row_list, i)))
+       continue;
 
-      gdk_window_show (clist->column[last_button].window);
-      gdk_window_move_resize (clist->column[last_button].window,
-                             button_allocation.x - (DRAG_WIDTH / 2), 
-                             0, DRAG_WIDTH, clist->column_title_area.height);
+      GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
+      if (CLIST_UNFROZEN (clist) &&
+         gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
+       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
+                                             GTK_CLIST_ROW (work));
     }
-  else
-    gdk_window_hide (clist->column[last_button].window);
 }
 
 static void
-size_allocate_columns (GtkCList * clist)
+real_undo_selection (GtkCList *clist)
 {
-  gint xoffset = CELL_SPACING + COLUMN_INSET;
-  gint last_column;
-  gint width = 0;
-  gint i;
+  GList *work;
 
-  /* find last visible column and calculate correct column width */
-  for (last_column = clist->columns - 1;
-       last_column >= 0 && !clist->column[last_column].visible; last_column--);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (last_column < 0)
+  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
+      clist->selection_mode != GTK_SELECTION_EXTENDED)
     return;
 
-  for (i = 0; i < last_column; i++)
+  GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+
+  if (!(clist->undo_selection || clist->undo_unselection))
     {
-      if (!clist->column[i].visible)
-       continue;
-      clist->column[i].area.x = xoffset;
-      clist->column[i].area.width = clist->column[i].width;
-      xoffset += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
+      gtk_clist_unselect_all (clist);
+      return;
+    }
+
+  for (work = clist->undo_selection; work; work = work->next)
+    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                    GPOINTER_TO_INT (work->data), -1, NULL);
+
+  for (work = clist->undo_unselection; work; work = work->next)
+    {
+      /* g_print ("unselect %d\n",GPOINTER_TO_INT (work->data)); */
+      gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 
+                      GPOINTER_TO_INT (work->data), -1, NULL);
     }
 
-  if (clist->column[i].width_set)
-    width = clist->column[i].width;
-  else if (clist->column[i].title)
-    width = gdk_string_width (GTK_WIDGET (clist)->style->font,
-                             clist->column[i].title);
+  if (GTK_WIDGET_HAS_FOCUS(clist) && clist->focus_row != clist->undo_anchor)
+    {
+      gtk_clist_draw_focus (GTK_WIDGET (clist));
+      clist->focus_row = clist->undo_anchor;
+      gtk_clist_draw_focus (GTK_WIDGET (clist));
+    }
+  else
+    clist->focus_row = clist->undo_anchor;
+  
+  clist->undo_anchor = -1;
+  g_list_free (clist->undo_selection);
+  g_list_free (clist->undo_unselection);
+  clist->undo_selection = NULL;
+  clist->undo_unselection = NULL;
 
-  clist->column[i].area.x = xoffset;
-  clist->column[i].area.width = MAX (width,
-                                    clist->clist_window_width - xoffset -
-                                    (CELL_SPACING + COLUMN_INSET));
+  if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
+      clist->clist_window_height)
+    gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+  else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
+    gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
 }
 
-/*
- * SELECTION
- *   select_row
- *   real_select_row
- *   real_unselect_row
- *   get_selection_info
- */
 static void
-toggle_row (GtkCList * clist,
-           gint row,
-           gint column,
-           GdkEvent * event)
+set_anchor (GtkCList *clist,
+           gboolean  add_mode,
+           gint      anchor,
+           gint      undo_anchor)
 {
-  GtkCListRow *clist_row;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  
+  if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
+    return;
 
-  switch (clist->selection_mode)
-    {
-    case GTK_SELECTION_EXTENDED:
-    case GTK_SELECTION_MULTIPLE:
-    case GTK_SELECTION_SINGLE:
-
-      clist_row = g_list_nth (clist->row_list, row)->data;
-      if (clist_row->state == GTK_STATE_SELECTED)
-       {
-         unselect_row (clist, row, column, event);
-         return;
-       }
+  g_list_free (clist->undo_selection);
+  g_list_free (clist->undo_unselection);
+  clist->undo_selection = NULL;
+  clist->undo_unselection = NULL;
 
-    case GTK_SELECTION_BROWSE:
-      select_row (clist, row, column, event);
-      break;
+  if (add_mode)
+    fake_toggle_row (clist, anchor);
+  else
+    {
+      GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
+      clist->anchor_state = GTK_STATE_SELECTED;
     }
-}
-
-static void
-select_row (GtkCList * clist,
-           gint row,
-           gint column,
-           GdkEvent * event)
-{
-  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
-                  row, column, event);
-}
 
-static void
-unselect_row (GtkCList * clist,
-             gint row,
-             gint column,
-             GdkEvent * event)
-{
-  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
-                  row, column, event);
+  clist->anchor = anchor;
+  clist->drag_pos = anchor;
+  clist->undo_anchor = undo_anchor;
 }
 
 static void
-real_select_row (GtkCList * clist,
-                gint row,
-                gint column,
-                GdkEvent * event)
+resync_selection (GtkCList *clist,
+                 GdkEvent *event)
 {
-  GtkCListRow *clist_row;
+  gint i;
+  gint e;
+  gint row;
   GList *list;
-  gint sel_row;
-  gboolean row_selected;
+  GtkCListRow *clist_row;
 
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  if (clist->selection_mode != GTK_SELECTION_EXTENDED)
+    return;
 
-  if (row < 0 || row > (clist->rows - 1))
+  if (clist->anchor < 0 || clist->drag_pos < 0)
     return;
 
-  switch (clist->selection_mode)
-    {
-    case GTK_SELECTION_SINGLE:
-    case GTK_SELECTION_BROWSE:
+  gtk_clist_freeze (clist);
 
-      row_selected = FALSE;
-      list = clist->selection;
+  i = MIN (clist->anchor, clist->drag_pos);
+  e = MAX (clist->anchor, clist->drag_pos);
 
+  if (clist->undo_selection)
+    {
+      list = clist->selection;
+      clist->selection = clist->undo_selection;
+      clist->selection_end = g_list_last (clist->selection);
+      clist->undo_selection = list;
+      list = clist->selection;
       while (list)
        {
-         sel_row = GPOINTER_TO_INT (list->data);
+         row = GPOINTER_TO_INT (list->data);
          list = list->next;
-
-         if (row == sel_row)
-           row_selected = TRUE;
-         else
-           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 
-                            sel_row, column, event);
+         if (row < i || row > e)
+           {
+             clist_row = g_list_nth (clist->row_list, row)->data;
+             if (clist_row->selectable)
+               {
+                 clist_row->state = GTK_STATE_SELECTED;
+                 gtk_signal_emit (GTK_OBJECT (clist),
+                                  clist_signals[UNSELECT_ROW],
+                                  row, -1, event);
+                 clist->undo_selection = g_list_prepend
+                   (clist->undo_selection, GINT_TO_POINTER (row));
+               }
+           }
        }
+    }    
 
-      if (row_selected)
-       return;
-      
-    default:
-      break;
-    }
-
-  clist_row = (g_list_nth (clist->row_list, row))->data;
-
-  if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
-    return;
-
-  clist_row->state = GTK_STATE_SELECTED;
-  if (!clist->selection)
+  if (clist->anchor < clist->drag_pos)
     {
-      clist->selection = g_list_append (clist->selection,
-                                       GINT_TO_POINTER (row));
-      clist->selection_end = clist->selection;
+      for (list = g_list_nth (clist->row_list, i); i <= e;
+          i++, list = list->next)
+       if (GTK_CLIST_ROW (list)->selectable)
+         {
+           if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
+             {
+               if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
+                 {
+                   GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
+                   gtk_signal_emit (GTK_OBJECT (clist),
+                                    clist_signals[UNSELECT_ROW],
+                                    i, -1, event);
+                   clist->undo_selection =
+                     g_list_prepend (clist->undo_selection,
+                                     GINT_TO_POINTER (i));
+                 }
+             }
+           else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
+             {
+               GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
+               clist->undo_unselection =
+                 g_list_prepend (clist->undo_unselection,
+                                 GINT_TO_POINTER (i));
+             }
+         }
     }
   else
-    clist->selection_end = 
-      g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
+    {
+      for (list = g_list_nth (clist->row_list, e); i <= e;
+          e--, list = list->prev)
+       if (GTK_CLIST_ROW (list)->selectable)
+         {
+           if (g_list_find (clist->selection, GINT_TO_POINTER(e)))
+             {
+               if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
+                 {
+                   GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
+                   gtk_signal_emit (GTK_OBJECT (clist),
+                                    clist_signals[UNSELECT_ROW],
+                                    e, -1, event);
+                   clist->undo_selection =
+                     g_list_prepend (clist->undo_selection,
+                                     GINT_TO_POINTER (e));
+                 }
+             }
+           else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
+             {
+               GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
+               clist->undo_unselection =
+                 g_list_prepend (clist->undo_unselection,
+                                 GINT_TO_POINTER (e));
+             }
+         }
+    }
   
-  if (!GTK_CLIST_FROZEN (clist)
-      && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
-    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+  clist->undo_unselection = g_list_reverse (clist->undo_unselection);
+  for (list = clist->undo_unselection; list; list = list->next)
+    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                    GPOINTER_TO_INT (list->data), -1, event);
+
+  clist->anchor = -1;
+  clist->drag_pos = -1;
+
+  gtk_clist_thaw (clist);
 }
 
 static void
-real_unselect_row (GtkCList * clist,
-                  gint row,
-                  gint column,
-                  GdkEvent * event)
+update_extended_selection (GtkCList *clist,
+                          gint      row)
 {
-  GtkCListRow *clist_row;
-
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  gint i;
+  GList *list;
+  GdkRectangle area;
+  gint s1 = -1;
+  gint s2 = -1;
+  gint e1 = -1;
+  gint e2 = -1;
+  gint y1 = clist->clist_window_height;
+  gint y2 = clist->clist_window_height;
+  gint h1 = 0;
+  gint h2 = 0;
+  gint top;
 
-  if (row < 0 || row > (clist->rows - 1))
+  if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
     return;
 
-  clist_row = (g_list_nth (clist->row_list, row))->data;
+  if (row < 0)
+    row = 0;
+  if (row >= clist->rows)
+    row = clist->rows - 1;
 
-  if (clist_row->state == GTK_STATE_SELECTED)
+  /* extending downwards */
+  if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
     {
-      clist_row->state = GTK_STATE_NORMAL;
-
-      if (clist->selection_end && 
-         clist->selection_end->data == GINT_TO_POINTER (row))
-       clist->selection_end = clist->selection_end->prev;
-
-      clist->selection = g_list_remove (clist->selection,
-                                       GINT_TO_POINTER (row));
-      
-      if (!GTK_CLIST_FROZEN (clist)
-         && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
-       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
+      s2 = clist->drag_pos + 1;
+      e2 = row;
+    }
+  /* extending upwards */
+  else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
+    {
+      s2 = row;
+      e2 = clist->drag_pos - 1;
+    }
+  else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
+    {
+      e1 = clist->drag_pos;
+      /* row and drag_pos on different sides of anchor :
+        take back the selection between anchor and drag_pos,
+         select between anchor and row */
+      if (row < clist->anchor)
+       {
+         s1 = clist->anchor + 1;
+         s2 = row;
+         e2 = clist->anchor - 1;
+       }
+      /* take back the selection between anchor and drag_pos */
+      else
+       s1 = row + 1;
+    }
+  else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
+    {
+      s1 = clist->drag_pos;
+      /* row and drag_pos on different sides of anchor :
+        take back the selection between anchor and drag_pos,
+         select between anchor and row */
+      if (row > clist->anchor)
+       {
+         e1 = clist->anchor - 1;
+         s2 = clist->anchor + 1;
+         e2 = row;
+       }
+      /* take back the selection between anchor and drag_pos */
+      else
+       e1 = row - 1;
     }
-}
 
-static gint
-get_selection_info (GtkCList * clist,
-                   gint x,
-                   gint y,
-                   gint * row,
-                   gint * column)
-{
-  gint trow, tcol;
+  clist->drag_pos = row;
 
-  g_return_val_if_fail (clist != NULL, 0);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
+  area.x = 0;
+  area.width = clist->clist_window_width;
 
-  /* bounds checking, return false if the user clicked 
-   * on a blank area */
-  trow = ROW_FROM_YPIXEL (clist, y);
-  if (trow >= clist->rows)
-    return 0;
+  /* restore the elements between s1 and e1 */
+  if (s1 >= 0)
+    {
+      for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
+          i++, list = list->next)
+       if (GTK_CLIST_ROW (list)->selectable)
+         {
+           if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
+             GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
+           else
+             GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
+         }
 
-  if (row)
-    *row = trow;
+      top = ROW_TOP_YPIXEL (clist, clist->focus_row);
 
-  tcol = COLUMN_FROM_XPIXEL (clist, x);
-  if (tcol >= clist->columns)
-    return 0;
+      if (top + clist->row_height <= 0)
+       {
+         area.y = 0;
+         area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
+         draw_rows (clist, &area);
+         gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+       }
+      else if (top >= clist->clist_window_height)
+       {
+         area.y = ROW_TOP_YPIXEL (clist, s1) - 1;
+         area.height = clist->clist_window_height - area.y;
+         draw_rows (clist, &area);
+         gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+       }
+      else if (top < 0)
+       gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+      else if (top + clist->row_height > clist->clist_window_height)
+       gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
 
-  if (column)
-    *column = tcol;
+      y1 = ROW_TOP_YPIXEL (clist, s1) - 1;
+      h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
+    }
 
-  return 1;
-}
-
-gint
-gtk_clist_get_selection_info (GtkCList *clist, 
-                             gint      x, 
-                             gint      y, 
-                             gint *    row, 
-                             gint *    column)
-{
-  g_return_val_if_fail (clist != NULL, 0);
-  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
-  return get_selection_info (clist, x, y, row, column);
-}
-
-/* 
- * RESIZE COLUMNS
- *   draw_xor_line
- *   new_column_width
- *   resize_column
- */
-static void                          
-draw_xor_line (GtkCList * clist)
-{
-  GtkWidget *widget;
-
-  g_return_if_fail (clist != NULL);
-
-  widget = GTK_WIDGET (clist);
-
-  gdk_draw_line (widget->window, clist->xor_gc,
-                 clist->x_drag,
-                widget->style->klass->ythickness,
-                 clist->x_drag,
-                 clist->column_title_area.height +
-                clist->clist_window_height + 1);
-}
-
-/* this function returns the new width of the column being resized given
- * the column and x position of the cursor; the x cursor position is passed
- * in as a pointer and automagicly corrected if it's beyond min/max limits */
-static gint
-new_column_width (GtkCList *clist,
-                 gint      column,
-                 gint     *x)
-{
-  gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness;
-  gint width;
-  gint cx;
-  gint dx;
+  /* extend the selection between s2 and e2 */
+  if (s2 >= 0)
+    {
+      for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
+          i++, list = list->next)
+       if (GTK_CLIST_ROW (list)->selectable &&
+           GTK_CLIST_ROW (list)->state != clist->anchor_state)
+         GTK_CLIST_ROW (list)->state = clist->anchor_state;
 
-  /* first translate the x position from widget->window
-   * to clist->clist_window */
-  cx = *x - xthickness;
+      top = ROW_TOP_YPIXEL (clist, clist->focus_row);
 
-  /* calculate new column width making sure it doesn't end up
-   * less than the minimum width */
-  dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
-       (column < clist->columns - 1) * CELL_SPACING);
-  width = cx - dx;
+      if (top + clist->row_height <= 0)
+       {
+         area.y = 0;
+         area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
+         draw_rows (clist, &area);
+         gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+       }
+      else if (top >= clist->clist_window_height)
+       {
+         area.y = ROW_TOP_YPIXEL (clist, s2) - 1;
+         area.height = clist->clist_window_height - area.y;
+         draw_rows (clist, &area);
+         gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+       }
+      else if (top < 0)
+       gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+      else if (top + clist->row_height > clist->clist_window_height)
+       gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
 
-  if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
-    {
-      width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
-      cx = dx + width;
-      *x = cx + xthickness;
+      y2 = ROW_TOP_YPIXEL (clist, s2) - 1;
+      h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
     }
-  else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
-          width > clist->column[column].max_width)
-    {
-      width = clist->column[column].max_width;
-      cx = dx + clist->column[column].max_width;
-      *x = cx + xthickness;
-    }      
-
-  if (cx < 0 || cx > clist->clist_window_width)
-    *x = -1;
 
-  return width;
+  area.y = MAX (0, MIN (y1, y2));
+  if (area.y > clist->clist_window_height)
+    area.y = 0;
+  area.height = MIN (clist->clist_window_height, h1 + h2);
+  if (s1 >= 0 && s2 >= 0)
+    area.height += (clist->row_height + CELL_SPACING);
+  draw_rows (clist, &area);
 }
 
-/* this will do more later */
 static void
-resize_column (GtkCList * clist,
-              gint column,
-              gint width)
+start_selection (GtkCList *clist)
 {
-  gtk_clist_set_column_width (clist, column, width);
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
+    return;
+
+  set_anchor (clist, GTK_CLIST_ADD_MODE(clist), clist->focus_row,
+             clist->focus_row);
 }
 
-/* BUTTONS */
 static void
-column_button_create (GtkCList * clist,
-                     gint column)
+end_selection (GtkCList *clist)
 {
-  GtkWidget *button;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  button = clist->column[column].button = gtk_button_new ();
-  if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
-    gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
-  gtk_widget_set_parent (button, GTK_WIDGET (clist));
-  
-  gtk_signal_connect (GTK_OBJECT (button), "clicked",
-                     (GtkSignalFunc) column_button_clicked,
-                     (gpointer) clist);
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS(clist))
+    return;
 
-  gtk_widget_show (button);
+  GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
 }
 
 static void
-column_button_clicked (GtkWidget * widget,
-                      gpointer data)
+extend_selection (GtkCList      *clist,
+                 GtkScrollType  scroll_type,
+                 gfloat         position,
+                 gboolean       auto_start_selection)
 {
-  gint i;
-  GtkCList *clist;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (data));
+  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
+      clist->selection_mode != GTK_SELECTION_EXTENDED)
+    return;
 
-  clist = GTK_CLIST (data);
+  if (auto_start_selection)
+    set_anchor (clist, GTK_CLIST_ADD_MODE(clist), clist->focus_row,
+               clist->focus_row);
+  else if (clist->anchor == -1)
+    return;
 
-  /* find the column who's button was pressed */
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].button == widget)
-      break;
+  move_focus_row (clist, scroll_type, position);
 
-  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
+  if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
+      clist->clist_window_height)
+    gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+  else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
+    gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+
+  update_extended_selection (clist, clist->focus_row);
 }
 
-/* 
- * SCROLLBARS
- *
- * functions:
- *   create_scrollbars
- *   adjust_scrollbars
- *   vadjustment_changed
- *   hadjustment_changed
- *   vadjustment_value_changed
- *   hadjustment_value_changed 
- */
 static void
-create_scrollbars (GtkCList * clist)
+sync_selection (GtkCList *clist,
+               gint      row,
+               gint      mode)
 {
-  GtkAdjustment *adjustment;
-
-  clist->vscrollbar = gtk_vscrollbar_new (NULL);
-
-  adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
-
-  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
-                     (GtkSignalFunc) vadjustment_changed,
-                     (gpointer) clist);
-
-  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
-                     (GtkSignalFunc) vadjustment_value_changed,
-                     (gpointer) clist);
+  GList *list;
+  gint d;
 
-  gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
-  gtk_widget_show (clist->vscrollbar);
+  if (mode == SYNC_INSERT)
+    d = 1;
+  else
+    d = -1;
+      
+  if (clist->focus_row >= row)
+    {
+      if (d > 0 || clist->focus_row > row)
+       clist->focus_row += d;
+      if (clist->focus_row == -1 && clist->rows >= 1)
+       clist->focus_row = 0;
+      else if (clist->focus_row >= clist->rows)
+       clist->focus_row = clist->rows - 1;
+    }
 
-  clist->hscrollbar = gtk_hscrollbar_new (NULL);
+  GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
 
-  adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
+  g_list_free (clist->undo_selection);
+  g_list_free (clist->undo_unselection);
+  clist->undo_selection = NULL;
+  clist->undo_unselection = NULL;
 
-  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
-                     (GtkSignalFunc) hadjustment_changed,
-                     (gpointer) clist);
+  clist->anchor = -1;
+  clist->drag_pos = -1;
+  clist->undo_anchor = clist->focus_row;
 
-  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
-                     (GtkSignalFunc) hadjustment_value_changed,
-                     (gpointer) clist);
+  list = clist->selection;
 
-  gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
-  gtk_widget_show (clist->hscrollbar);
+  while (list)
+    {
+      if (GPOINTER_TO_INT (list->data) >= row)
+       list->data = ((gchar*) list->data) + d;
+      list = list->next;
+    }
 }
 
+/* GTKOBJECT
+ *   gtk_clist_destroy
+ *   gtk_clist_finalize
+ */
 static void
-adjust_scrollbars (GtkCList * clist)
+gtk_clist_destroy (GtkObject *object)
 {
-  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);
+  gint i;
+  GtkCList *clist;
 
-  if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
-    {
-      GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) - 
-       clist->clist_window_height);
-      gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
-                              "value_changed");
-    }
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_CLIST (object));
 
-  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);
+  clist = GTK_CLIST (object);
 
-  if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
-    {
-      GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) - 
-       clist->clist_window_width);
-      gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
-                              "value_changed");
-    }
+  /* freeze the list */
+  clist->freeze_count++;
 
-  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_size_allocate (GTK_WIDGET (clist),
-                                   &GTK_WIDGET (clist)->allocation);
-       }
-    }
-  else
-    {
-      if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
-       {
-         gtk_widget_show (clist->vscrollbar);
-         gtk_widget_size_allocate (GTK_WIDGET (clist),
-                                   &GTK_WIDGET (clist)->allocation);
-       }
-    }
+  /* get rid of all the rows */
+  gtk_clist_clear (clist);
+
+  /* Since we don't have a _remove method, unparent the children
+   * instead of destroying them so the focus will be unset properly.
+   * (For other containers, the _remove method takes care of the
+   * unparent) The destroy will happen when the refcount drops
+   * to zero.
+   */
 
-  if (LIST_WIDTH (clist) <= clist->clist_window_width &&
-      clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
+  /* unref adjustments */
+  if (clist->hadjustment)
     {
-      if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
-       {
-         gtk_widget_hide (clist->hscrollbar);
-         gtk_widget_size_allocate (GTK_WIDGET (clist),
-                                   &GTK_WIDGET (clist)->allocation);
-       }
+      gtk_signal_disconnect_by_data (GTK_OBJECT (clist->hadjustment), clist);
+      gtk_object_unref (GTK_OBJECT (clist->hadjustment));
+      clist->hadjustment = NULL;
     }
-  else
+  if (clist->vadjustment)
     {
-      if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
-       {
-         gtk_widget_show (clist->hscrollbar);
-         gtk_widget_size_allocate (GTK_WIDGET (clist),
-                                   &GTK_WIDGET (clist)->allocation);
-       }
+      gtk_signal_disconnect_by_data (GTK_OBJECT (clist->vadjustment), clist);
+      gtk_object_unref (GTK_OBJECT (clist->vadjustment));
+      clist->vadjustment = NULL;
     }
 
-  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
-vadjustment_changed (GtkAdjustment * adjustment,
-                              gpointer data)
-{
-  GtkCList *clist;
+  remove_grab (clist);
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+  /* destroy the column buttons */
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].button)
+      {
+       gtk_widget_unparent (clist->column[i].button);
+       clist->column[i].button = NULL;
+      }
 
-  clist = GTK_CLIST (data);
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }
 
 static void
-hadjustment_changed (GtkAdjustment * adjustment,
-                              gpointer data)
+gtk_clist_finalize (GtkObject *object)
 {
   GtkCList *clist;
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_CLIST (object));
 
-  clist = GTK_CLIST (data);
-}
+  clist = GTK_CLIST (object);
 
-static void
-check_exposures (GtkCList *clist)
-{
-  GdkEvent *event;
+  columns_delete (clist);
 
-  if (!GTK_WIDGET_REALIZED (clist))
-    return;
+  g_mem_chunk_destroy (clist->cell_mem_chunk);
+  g_mem_chunk_destroy (clist->row_mem_chunk);
 
-  /* Make sure graphics expose events are processed before scrolling
-   * again */
-  while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
-    {
-      gtk_widget_event (GTK_WIDGET (clist), event);
-      if (event->expose.count == 0)
-       {
-         gdk_event_free (event);
-         break;
-       }
-      gdk_event_free (event);
-    }
+  if (GTK_OBJECT_CLASS (parent_class)->finalize)
+    (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
 }
 
+/* GTKWIDGET
+ *   gtk_clist_realize
+ *   gtk_clist_unrealize
+ *   gtk_clist_map
+ *   gtk_clist_unmap
+ *   gtk_clist_draw
+ *   gtk_clist_expose
+ *   gtk_clist_style_set
+ *   gtk_clist_key_press
+ *   gtk_clist_button_press
+ *   gtk_clist_button_release
+ *   gtk_clist_motion
+ *   gtk_clist_size_request
+ *   gtk_clist_size_allocate
+ */
 static void
-vadjustment_value_changed (GtkAdjustment * adjustment,
-                                    gpointer data)
+gtk_clist_realize (GtkWidget *widget)
 {
   GtkCList *clist;
-  GdkRectangle area;
-  gint diff, value;
+  GdkWindowAttr attributes;
+  GdkGCValues values;
+  GtkCListRow *clist_row;
+  GList *list;
+  gint attributes_mask;
+  gint border_width;
+  gint i;
+  gint j;
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
-  g_return_if_fail (GTK_IS_CLIST (data));
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
 
-  clist = GTK_CLIST (data);
+  clist = GTK_CLIST (widget);
 
-  if (!GTK_WIDGET_DRAWABLE (clist))
-    return;
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
-  value = adjustment->value;
+  border_width = GTK_CONTAINER (widget)->border_width;
+  
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x + border_width;
+  attributes.y = widget->allocation.y + border_width;
+  attributes.width = widget->allocation.width - border_width * 2;
+  attributes.height = widget->allocation.height - border_width * 2;
+  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 |
+                           GDK_KEY_RELEASE_MASK);
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 
-  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
-    {
-      if (value > -clist->voffset)
-       {
-         /* scroll down */
-         diff = value + clist->voffset;
+  /* main window */
+  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                                  &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, clist);
 
-         /* we have to re-draw the whole screen here... */
-         if (diff >= clist->clist_window_height)
-           {
-             clist->voffset = -value;
-             draw_rows (clist, NULL);
-             return;
-           }
+  widget->style = gtk_style_attach (widget->style, widget->window);
 
-         if ((diff != 0) && (diff != clist->clist_window_height))
-           gdk_window_copy_area (clist->clist_window,
-                                 clist->fg_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;
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
 
-         /* we have to re-draw the whole screen here... */
-         if (diff >= clist->clist_window_height)
-           {
-             clist->voffset = -value;
-             draw_rows (clist, NULL);
-             return;
-           }
+  /* column-title window */
 
-         if ((diff != 0) && (diff != clist->clist_window_height))
-           gdk_window_copy_area (clist->clist_window,
-                                 clist->fg_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;
+  attributes.x = clist->column_title_area.x;
+  attributes.y = clist->column_title_area.y;
+  attributes.width = clist->column_title_area.width;
+  attributes.height = clist->column_title_area.height;
+  
+  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_NORMAL);
+  gdk_window_show (clist->title_window);
 
-      clist->voffset = -value;
-      if ((diff != 0) && (diff != clist->clist_window_height))
-       check_exposures (clist);
+  /* set things up so column buttons are drawn in title window */
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].button)
+      gtk_widget_set_parent_window (clist->column[i].button,
+                                   clist->title_window);
+
+  /* clist-window */
+  attributes.x = (clist->internal_allocation.x +
+                 widget->style->klass->xthickness);
+  attributes.y = (clist->internal_allocation.y +
+                 widget->style->klass->ythickness +
+                 clist->column_title_area.height);
+  attributes.width = clist->clist_window_width;
+  attributes.height = clist->clist_window_height;
+  
+  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->base[GTK_STATE_NORMAL]);
+  gdk_window_show (clist->clist_window);
+  gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
+                      &clist->clist_window_height);
+
+  /* create resize windows */
+  attributes.wclass = GDK_INPUT_ONLY;
+  attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK |
+                          GDK_POINTER_MOTION_MASK |
+                          GDK_POINTER_MOTION_HINT_MASK |
+                          GDK_KEY_PRESS_MASK);
+  attributes_mask = GDK_WA_CURSOR;
+  attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+  clist->cursor_drag = attributes.cursor;
+
+  attributes.x =  LIST_WIDTH (clist) + 1;
+  attributes.y = 0;
+  attributes.width = 0;
+  attributes.height = 0;
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      clist->column[i].window = gdk_window_new (clist->title_window,
+                                               &attributes, attributes_mask);
+      gdk_window_set_user_data (clist->column[i].window, clist);
     }
 
-  draw_rows (clist, &area);
+  /* This is slightly less efficient than creating them with the
+   * right size to begin with, but easier
+   */
+  size_allocate_title_buttons (clist);
+
+  /* GCs */
+  clist->fg_gc = gdk_gc_new (widget->window);
+  clist->bg_gc = gdk_gc_new (widget->window);
+  
+  /* We'll use this gc to do scrolling as well */
+  gdk_gc_set_exposures (clist->fg_gc, TRUE);
+
+  values.foreground = (widget->style->white.pixel==0 ?
+                      widget->style->black: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);
+
+  /* attach optional row/cell styles, allocate foreground/background colors */
+  list = clist->row_list;
+  for (i = 0; i < clist->rows; i++)
+    {
+      clist_row = list->data;
+      list = list->next;
+
+      if (clist_row->style)
+       clist_row->style = gtk_style_attach (clist_row->style,
+                                            clist->clist_window);
+
+      if (clist_row->fg_set || clist_row->bg_set)
+       {
+         GdkColormap *colormap;
+
+         colormap = gtk_widget_get_colormap (widget);
+         if (clist_row->fg_set)
+           gdk_color_alloc (colormap, &clist_row->foreground);
+         if (clist_row->bg_set)
+           gdk_color_alloc (colormap, &clist_row->background);
+       }
+      
+      for (j = 0; j < clist->columns; j++)
+       if  (clist_row->cell[j].style)
+         clist_row->cell[j].style =
+           gtk_style_attach (clist_row->cell[j].style, clist->clist_window);
+    }
 }
 
 static void
-hadjustment_value_changed (GtkAdjustment * adjustment,
-                                    gpointer data)
+gtk_clist_unrealize (GtkWidget *widget)
 {
-  GtkCList *clist;
-  GdkRectangle area;
   gint i;
-  gint y = 0;
-  gint diff = 0;
-  gint value;
+  GtkCList *clist;
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
-  g_return_if_fail (GTK_IS_CLIST (data));
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
 
-  clist = GTK_CLIST (data);
+  clist = GTK_CLIST (widget);
 
-  if (!GTK_WIDGET_DRAWABLE (clist) ||
-      adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
-    return;
+  /* freeze the list */
+  clist->freeze_count++;
 
-  value = adjustment->value;
-  
-  /* move the column buttons and resize windows */
-  for (i = 0; i < clist->columns; i++)
+  if (GTK_WIDGET_MAPPED (widget))
+    gtk_clist_unmap (widget);
+
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+
+  /* detach optional row/cell styles */
+  if (GTK_WIDGET_REALIZED (widget))
     {
-      if (clist->column[i].button)
+      GtkCListRow *clist_row;
+      GList *list;
+      gint j;
+
+      list = clist->row_list;
+      for (i = 0; i < clist->rows; 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 (clist->column[i].window)
-               gdk_window_move (clist->column[i].window,
-                                clist->column[i].button->allocation.x +
-                                clist->column[i].button->allocation.width - 
-                                (DRAG_WIDTH / 2), 0); 
-           }
+         clist_row = list->data;
+         list = list->next;
+
+         if (clist_row->style)
+           gtk_style_detach (clist_row->style);
+         for (j = 0; j < clist->columns; j++)
+           if  (clist_row->cell[j].style)
+             gtk_style_detach (clist_row->cell[j].style);
        }
     }
 
-  if (value > -clist->hoffset)
+  gdk_cursor_destroy (clist->cursor_drag);
+  gdk_gc_destroy (clist->xor_gc);
+  gdk_gc_destroy (clist->fg_gc);
+  gdk_gc_destroy (clist->bg_gc);
+
+  for (i = 0; i < clist->columns; i++)
     {
-      /* scroll right */
-      diff = value + clist->hoffset;
-      
-      clist->hoffset = -value;
-      
-      /* we have to re-draw the whole screen here... */
-      if (diff >= clist->clist_window_width)
+      if (clist->column[i].button)
+       gtk_widget_unrealize (clist->column[i].button);
+      if (clist->column[i].window)
        {
-         draw_rows (clist, NULL);
-         return;
+         gdk_window_set_user_data (clist->column[i].window, NULL);
+         gdk_window_destroy (clist->column[i].window);
+         clist->column[i].window = NULL;
        }
+    }
 
-      if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
-         GTK_CLIST_ADD_MODE (clist))
-       {
-         y = ROW_TOP_YPIXEL (clist, clist->focus_row);
-             
-         gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
-                             clist->clist_window_width - 1,
-                             clist->row_height - 1);
-       }
-      gdk_window_copy_area (clist->clist_window,
-                           clist->fg_gc,
-                           0, 0,
-                           clist->clist_window,
-                           diff,
-                           0,
-                           clist->clist_window_width - diff,
-                           clist->clist_window_height);
+  gdk_window_set_user_data (clist->clist_window, NULL);
+  gdk_window_destroy (clist->clist_window);
+  clist->clist_window = NULL;
 
-      area.x = clist->clist_window_width - diff;
-    }
-  else
-    {
-      /* scroll left */
-      if (!(diff = -clist->hoffset - value))
-       return;
+  gdk_window_set_user_data (clist->title_window, NULL);
+  gdk_window_destroy (clist->title_window);
+  clist->title_window = NULL;
 
-      clist->hoffset = -value;
-      
-      /* we have to re-draw the whole screen here... */
-      if (diff >= clist->clist_window_width)
-       {
-         draw_rows (clist, NULL);
-         return;
-       }
-      
-      if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
-         GTK_CLIST_ADD_MODE (clist))
-       {
-         y = ROW_TOP_YPIXEL (clist, clist->focus_row);
-         
-         gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
-                             clist->clist_window_width - 1,
-                             clist->row_height - 1);
-       }
+  clist->cursor_drag = NULL;
+  clist->xor_gc = NULL;
+  clist->fg_gc = NULL;
+  clist->bg_gc = NULL;
 
-      gdk_window_copy_area (clist->clist_window,
-                           clist->fg_gc,
-                           diff, 0,
-                           clist->clist_window,
-                           0,
-                           0,
-                           clist->clist_window_width - diff,
-                           clist->clist_window_height);
-         
-      area.x = 0;
-    }
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
 
-  area.y = 0;
-  area.width = diff;
-  area.height = clist->clist_window_height;
+static void
+gtk_clist_map (GtkWidget *widget)
+{
+  gint i;
+  GtkCList *clist;
 
-  check_exposures (clist);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+
+  clist = GTK_CLIST (widget);
 
-  if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
+  if (!GTK_WIDGET_MAPPED (widget))
     {
-      if (GTK_CLIST_ADD_MODE (clist))
-       {
-         gint focus_row;
-         
-         focus_row = clist->focus_row;
-         clist->focus_row = -1;
-         draw_rows (clist, &area);
-         clist->focus_row = focus_row;
-         
-         gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
-                             FALSE, 0, y, clist->clist_window_width - 1,
-                             clist->row_height - 1);
-         return;
-       }
-      else
+      GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+
+      /* map column buttons */
+      for (i = 0; i < clist->columns; i++)
        {
-         gint x0;
-         gint x1;
-         
-         if (area.x == 0)
-           {
-             x0 = clist->clist_window_width - 1;
-             x1 = diff;
-           }
-         else
-           {
-             x0 = 0;
-             x1 = area.x - 1;
-           }
-         
-         y = ROW_TOP_YPIXEL (clist, clist->focus_row);
-         gdk_draw_line (clist->clist_window, clist->xor_gc,
-                        x0, y + 1, x0, y + clist->row_height - 2);
-         gdk_draw_line (clist->clist_window, clist->xor_gc,
-                        x1, y + 1, x1, y + clist->row_height - 2);
-         
+         if (clist->column[i].button &&
+             GTK_WIDGET_VISIBLE (clist->column[i].button) &&
+             !GTK_WIDGET_MAPPED (clist->column[i].button))
+           gtk_widget_map (clist->column[i].button);
        }
+      
+      for (i = 0; i < clist->columns; i++)
+       if (clist->column[i].window && clist->column[i].button)
+         {
+           gdk_window_raise (clist->column[i].window);
+           gdk_window_show (clist->column[i].window);
+         }
+
+      gdk_window_show (clist->title_window);
+      gdk_window_show (clist->clist_window);
+      gdk_window_show (widget->window);
+
+      /* unfreeze the list */
+      clist->freeze_count = 0;
     }
-  draw_rows (clist, &area);
 }
 
-/* 
- * Memory Allocation/Distruction Routines for GtkCList stuctures
- *
- * functions:
- *   columns_new
- *   column_title_new
- *   columns_delete
- *   row_new
- *   row_delete
- *   set_cell_contents 
- */
-static GtkCListColumn *
-columns_new (GtkCList * clist)
+static void
+gtk_clist_unmap (GtkWidget *widget)
 {
   gint i;
-  GtkCListColumn *column;
+  GtkCList *clist;
 
-  column = g_new (GtkCListColumn, clist->columns);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
 
-  for (i = 0; i < clist->columns; i++)
+  clist = GTK_CLIST (widget);
+
+  if (GTK_WIDGET_MAPPED (widget))
     {
-      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].window = NULL;
-      column[i].width = 0;
-      column[i].min_width = -1;
-      column[i].max_width = -1;
-      column[i].visible = TRUE;
-      column[i].width_set = FALSE;
-      column[i].resizeable = TRUE;
-      column[i].justification = GTK_JUSTIFY_LEFT;
-    }
+      GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
 
-  return column;
-}
+      if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
+       {
+         remove_grab (clist);
 
-static void
-column_title_new (GtkCList    *clist,
-                 gint         column,
-                 const gchar *title)
-{
-  if (clist->column[column].title)
-    g_free (clist->column[column].title);
+         GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, NULL);
 
-  clist->column[column].title = g_strdup (title);
-}
+         clist->click_cell.row = -1;
+         clist->click_cell.column = -1;
+         clist->drag_button = 0;
 
-static void
-columns_delete (GtkCList * clist)
-{
-  gint i;
+         if (GTK_CLIST_IN_DRAG(clist))
+           {
+             gpointer drag_data;
+
+             GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
+             drag_data = gtk_object_get_data (GTK_OBJECT (clist),
+                                              "gtk-site-data");
+             if (drag_data)
+               gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist),
+                                                   drag_data);
+           }
+       }
 
-  for (i = 0; i < clist->columns; i++)
-    if (clist->column[i].title)
-      g_free (clist->column[i].title);
-      
-  g_free (clist->column);
+      for (i = 0; i < clist->columns; i++)
+       if (clist->column[i].window)
+         gdk_window_hide (clist->column[i].window);
+
+      gdk_window_hide (clist->clist_window);
+      gdk_window_hide (clist->title_window);
+      gdk_window_hide (widget->window);
+
+      /* unmap column buttons */
+      for (i = 0; i < clist->columns; i++)
+       if (clist->column[i].button &&
+           GTK_WIDGET_MAPPED (clist->column[i].button))
+         gtk_widget_unmap (clist->column[i].button);
+
+      /* freeze the list */
+      clist->freeze_count++;
+    }
 }
 
-static GtkCListRow *
-row_new (GtkCList * clist)
+static void
+gtk_clist_draw (GtkWidget    *widget,
+               GdkRectangle *area)
 {
+  GtkCList *clist;
+  gint border_width;
+  GdkRectangle child_area;
   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);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (area != NULL);
 
-  for (i = 0; i < clist->columns; i++)
+  if (GTK_WIDGET_DRAWABLE (widget))
     {
-      clist_row->cell[i].type = GTK_CELL_EMPTY;
-      clist_row->cell[i].vertical = 0;
-      clist_row->cell[i].horizontal = 0;
-    }
+      clist = GTK_CLIST (widget);
+      border_width = GTK_CONTAINER (widget)->border_width;
 
-  clist_row->fg_set = FALSE;
-  clist_row->bg_set = FALSE;
-  clist_row->selectable = TRUE;
-  clist_row->state = GTK_STATE_NORMAL;
-  clist_row->data = NULL;
-  clist_row->destroy = NULL;
+      gdk_window_clear_area (widget->window,
+                            area->x - border_width, 
+                            area->y - border_width,
+                            area->width, area->height);
 
-  return clist_row;
+      /* draw list shadow/border */
+      gtk_draw_shadow (widget->style, widget->window,
+                      GTK_STATE_NORMAL, clist->shadow_type,
+                      0, 0, 
+                      clist->clist_window_width +
+                      (2 * widget->style->klass->xthickness),
+                      clist->clist_window_height +
+                      (2 * widget->style->klass->ythickness) +
+                      clist->column_title_area.height);
+
+      gdk_window_clear_area (clist->clist_window, 0, 0, 0, 0);
+      draw_rows (clist, NULL);
+
+      for (i = 0; i < clist->columns; i++)
+       {
+         if (!clist->column[i].visible)
+           continue;
+         if (clist->column[i].button &&
+             gtk_widget_intersect(clist->column[i].button, area, &child_area))
+           gtk_widget_draw (clist->column[i].button, &child_area);
+       }
+    }
 }
 
-static void
-row_delete (GtkCList * clist,
-           GtkCListRow * clist_row)
+static gint
+gtk_clist_expose (GtkWidget      *widget,
+                 GdkEventExpose *event)
 {
-  gint i;
+  GtkCList *clist;
 
-  for (i = 0; i < clist->columns; i++)
-    GTK_CLIST_CLASS_FW (clist)->set_cell_contents
-      (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
+  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 (clist_row->destroy)
-    clist_row->destroy (clist_row->data);
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      clist = GTK_CLIST (widget);
 
-  g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
-  g_mem_chunk_free (clist->row_mem_chunk, clist_row);
+      /* draw border */
+      if (event->window == widget->window)
+       gtk_draw_shadow (widget->style, widget->window,
+                        GTK_STATE_NORMAL, clist->shadow_type,
+                        0, 0,
+                        clist->clist_window_width +
+                        (2 * widget->style->klass->xthickness),
+                        clist->clist_window_height +
+                        (2 * widget->style->klass->ythickness) +
+                        clist->column_title_area.height);
+
+      /* exposure events on the list */
+      if (event->window == clist->clist_window)
+       draw_rows (clist, &event->area);
+    }
+
+  return FALSE;
 }
 
 static void
-set_cell_contents (GtkCList    *clist,
-                  GtkCListRow *clist_row,
-                  gint         column,
-                  GtkCellType  type,
-                  const gchar *text,
-                  guint8       spacing,
-                  GdkPixmap   *pixmap,
-                  GdkBitmap   *mask)
+gtk_clist_style_set (GtkWidget *widget,
+                    GtkStyle  *previous_style)
 {
-  g_return_if_fail (clist_row != NULL);
+  GtkCList *clist;
 
-  switch (clist_row->cell[column].type)
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+
+  if (GTK_WIDGET_CLASS (parent_class)->style_set)
+    (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
+
+  clist = GTK_CLIST (widget);
+
+  if (GTK_WIDGET_REALIZED (widget))
     {
-    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);
-      if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
-       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);
-      if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
-       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;
-
-  switch (type)
-    {
-    case GTK_CELL_TEXT:
-      if (text)
-       {
-         clist_row->cell[column].type = GTK_CELL_TEXT;
-         GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
-       }
-      break;
-
-    case GTK_CELL_PIXMAP:
-      if (pixmap)
-       {
-         clist_row->cell[column].type = GTK_CELL_PIXMAP;
-         GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
-         /* We set the mask even if it is NULL */
-         GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
-       }
-      break;
-
-    case GTK_CELL_PIXTEXT:
-      if (text && pixmap)
-       {
-         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;
-       }
-      break;
-
-    default:
-      break;
+      gtk_style_set_background (widget->style, widget->window, widget->state);
+      gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
+      gdk_window_set_background (clist->clist_window, &widget->style->base[GTK_STATE_NORMAL]);
     }
-}
-
-/* Fill in data after widget has correct style */
-
-static void 
-add_style_data (GtkCList * clist)
-{
-  GtkWidget *widget;
 
-  widget = GTK_WIDGET(clist);
+  /* Fill in data after widget has correct style */
 
   /* text properties */
-  if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
+  if (!GTK_CLIST_ROW_HEIGHT_SET(clist))
     {
-      clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
+      clist->row_height = (widget->style->font->ascent +
+                          widget->style->font->descent + 1);
       clist->row_center_offset = widget->style->font->ascent + 1.5;
     }
   else
-    {
-      gint text_height;
-      text_height = clist->row_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;
-    }
+    clist->row_center_offset = 1.5 + (clist->row_height +
+                                     widget->style->font->ascent -
+                                     widget->style->font->descent - 1) / 2;
 
   /* Column widths */
-}
-
-
-/* focus functions */
-
-static void
-gtk_clist_draw_focus (GtkWidget *widget)
-{
-  GtkCList *clist;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_CLIST (widget));
-
-  if (!GTK_WIDGET_DRAWABLE (widget))
-    return;
-
-  clist = GTK_CLIST (widget);
-  if (clist->focus_row >= 0)
-    gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
-                       0, ROW_TOP_YPIXEL(clist, clist->focus_row),
-                       clist->clist_window_width - 1,
-                       clist->row_height - 1);
-}
-
-static void
-gtk_clist_set_focus_child (GtkContainer *container,
-                          GtkWidget    *child)
-{
-  g_return_if_fail (container != NULL);
-  g_return_if_fail (GTK_IS_CLIST (container));
-
-  if (child)
+  if (!GTK_CLIST_AUTO_RESIZE_BLOCKED(clist))
     {
-      g_return_if_fail (GTK_IS_WIDGET (child));
-      GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
-    }
+      gint width;
+      gint i;
 
-  parent_class->set_focus_child (container, child);
+      for (i = 0; i < clist->columns; i++)
+       if (clist->column[i].auto_resize)
+         {
+           width = gtk_clist_optimal_column_width (clist, i);
+           if (width != clist->column[i].width)
+             gtk_clist_set_column_width (clist, i, width);
+         }
+    }
 }
 
 static gint
-gtk_clist_focus_in (GtkWidget     *widget,
-                   GdkEventFocus *event)
+gtk_clist_key_press (GtkWidget   *widget,
+                    GdkEventKey *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);
 
-  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
-  GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
-
-  clist = GTK_CLIST (widget);
+  if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
+      GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
+    return TRUE;
 
-  if (clist->selection_mode == GTK_SELECTION_BROWSE &&
-      clist->selection == NULL && clist->focus_row > -1)
+  switch (event->keyval)
     {
-      GList *list;
-
-      list = g_list_nth (clist->row_list, clist->focus_row);
-      if (list && GTK_CLIST_ROW (list)->selectable)
-       select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
+    case GDK_Tab:
+    case GDK_ISO_Left_Tab:
+      if (event->state & GDK_SHIFT_MASK)
+       return gtk_container_focus (GTK_CONTAINER (widget),
+                                   GTK_DIR_TAB_BACKWARD);
       else
-       gtk_widget_draw_focus (widget);
+       return gtk_container_focus (GTK_CONTAINER (widget),
+                                   GTK_DIR_TAB_FORWARD);
+    default:
+      break;
     }
-  else
-    gtk_widget_draw_focus (widget);
-
   return FALSE;
 }
 
 static gint
-gtk_clist_focus_out (GtkWidget     *widget,
-                    GdkEventFocus *event)
+gtk_clist_button_press (GtkWidget      *widget,
+                       GdkEventButton *event)
 {
+  gint i;
   GtkCList *clist;
+  gint x;
+  gint y;
+  gint row;
+  gint column;
+  gint button_actions;
 
   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);
 
-  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
-  gtk_widget_draw_focus (widget);
-  
   clist = GTK_CLIST (widget);
 
-  if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
-    GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
-
-  return FALSE;
-}
+  button_actions = clist->button_actions[event->button - 1];
 
-static void
-toggle_add_mode (GtkCList *clist)
-{
-  g_return_if_fail (clist != 0);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-  
-  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
-      clist->selection_mode != GTK_SELECTION_EXTENDED)
-    return;
+  if (button_actions == GTK_BUTTON_IGNORED)
+    return FALSE;
 
-  gtk_clist_draw_focus (GTK_WIDGET (clist));
-  if (!GTK_CLIST_ADD_MODE (clist))
-    {
-      GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
-      gdk_gc_set_line_attributes (clist->xor_gc, 1,
-                                 GDK_LINE_ON_OFF_DASH, 0, 0);
-      gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
-    }
-  else
+  /* selections on the list */
+  if (event->window == clist->clist_window)
     {
-      GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
-      gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
-      clist->anchor_state = GTK_STATE_SELECTED;
-    }
-  gtk_clist_draw_focus (GTK_WIDGET (clist));
-}
+      x = event->x;
+      y = event->y;
 
-static void
-toggle_focus_row (GtkCList *clist)
-{
-  g_return_if_fail (clist != 0);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+      if (get_selection_info (clist, x, y, &row, &column))
+       {
+         gint old_row = clist->focus_row;
 
-  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
-      clist->focus_row < 0 || clist->focus_row >= clist->rows)
-    return;
+         if (clist->focus_row == -1)
+           old_row = row;
 
-  switch (clist->selection_mode)
-    {
-    case  GTK_SELECTION_SINGLE:
-    case  GTK_SELECTION_MULTIPLE:
-      toggle_row (clist, clist->focus_row, 0, NULL);
-      break;
-    case GTK_SELECTION_EXTENDED:
-      g_list_free (clist->undo_selection);
-      g_list_free (clist->undo_unselection);
-      clist->undo_selection = NULL;
-      clist->undo_unselection = NULL;
+         if (event->type == GDK_BUTTON_PRESS)
+           {
+             GdkEventMask mask = ((1 << (4 + event->button)) |
+                                  GDK_POINTER_MOTION_HINT_MASK |
+                                  GDK_BUTTON_RELEASE_MASK);
 
-      clist->anchor = clist->focus_row;
-      clist->drag_pos = clist->focus_row;
-      clist->undo_anchor = clist->focus_row;
-      
-      if (GTK_CLIST_ADD_MODE (clist))
-       fake_toggle_row (clist, clist->focus_row);
-      else
-       GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
+             if (gdk_pointer_grab (clist->clist_window, FALSE, mask,
+                                   NULL, NULL, event->time))
+               return FALSE;
+             gtk_grab_add (widget);
 
-      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
-      break;
-    default:
-      break;
-    }
-}
+             clist->click_cell.row = row;
+             clist->click_cell.column = column;
+             clist->drag_button = event->button;
+           }
+         else
+           {
+             clist->click_cell.row = -1;
+             clist->click_cell.column = -1;
 
-static void
-move_focus_row (GtkCList      *clist,
-               GtkScrollType  scroll_type,
-               gfloat         position)
-{
-  GtkWidget *widget;
+             clist->drag_button = 0;
+             remove_grab (clist);
+           }
 
-  g_return_if_fail (clist != 0);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+         if (button_actions & GTK_BUTTON_SELECTS)
+           {
+             if (GTK_CLIST_ADD_MODE(clist))
+               {
+                 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
+                 if (GTK_WIDGET_HAS_FOCUS(widget))
+                   {
+                     gtk_clist_draw_focus (widget);
+                     gdk_gc_set_line_attributes (clist->xor_gc, 1,
+                                                 GDK_LINE_SOLID, 0, 0);
+                     clist->focus_row = row;
+                     gtk_clist_draw_focus (widget);
+                   }
+                 else
+                   {
+                     gdk_gc_set_line_attributes (clist->xor_gc, 1,
+                                                 GDK_LINE_SOLID, 0, 0);
+                     clist->focus_row = row;
+                   }
+               }
+             else if (row != clist->focus_row)
+               {
+                 if (GTK_WIDGET_HAS_FOCUS(widget))
+                   {
+                     gtk_clist_draw_focus (widget);
+                     clist->focus_row = row;
+                     gtk_clist_draw_focus (widget);
+                   }
+                 else
+                   clist->focus_row = row;
+               }
+           }
 
-  widget = GTK_WIDGET (clist);
+         if (!GTK_WIDGET_HAS_FOCUS(widget))
+           gtk_widget_grab_focus (widget);
 
-  switch (scroll_type)
-    {
-    case GTK_SCROLL_STEP_BACKWARD:
-      if (clist->focus_row <= 0)
-       return;
-      gtk_clist_draw_focus (widget);
-      clist->focus_row--;
-      gtk_clist_draw_focus (widget);
-      break;
-    case GTK_SCROLL_STEP_FORWARD:
-      if (clist->focus_row >= clist->rows - 1)
-       return;
-      gtk_clist_draw_focus (widget);
-      clist->focus_row++;
-      gtk_clist_draw_focus (widget);
-      break;
-    case GTK_SCROLL_PAGE_BACKWARD:
-      if (clist->focus_row <= 0)
-       return;
-      gtk_clist_draw_focus (widget);
-      clist->focus_row = MAX (0, clist->focus_row -
-                             (2 * clist->clist_window_height -
-                              clist->row_height - CELL_SPACING) / 
-                             (2 * (clist->row_height + CELL_SPACING)));
-      gtk_clist_draw_focus (widget);
-      break;
-    case GTK_SCROLL_PAGE_FORWARD:
-      if (clist->focus_row >= clist->rows - 1)
-       return;
-      gtk_clist_draw_focus (widget);
-      clist->focus_row = MIN (clist->rows - 1, clist->focus_row + 
-                             (2 * clist->clist_window_height -
-                              clist->row_height - CELL_SPACING) / 
-                             (2 * (clist->row_height + CELL_SPACING)));
-      gtk_clist_draw_focus (widget);
-      break;
-    case GTK_SCROLL_JUMP:
-      if (position >= 0 && position <= 1)
-       {
-         gtk_clist_draw_focus (widget);
-         clist->focus_row = position * (clist->rows - 1);
-         gtk_clist_draw_focus (widget);
+         if (button_actions & GTK_BUTTON_SELECTS)
+           {
+             switch (clist->selection_mode)
+               {
+               case GTK_SELECTION_SINGLE:
+               case GTK_SELECTION_MULTIPLE:
+                 if (event->type != GDK_BUTTON_PRESS)
+                   {
+                     gtk_signal_emit (GTK_OBJECT (clist),
+                                      clist_signals[SELECT_ROW],
+                                      row, column, event);
+                     clist->anchor = -1;
+                   }
+                 else
+                   clist->anchor = row;
+                 break;
+               case GTK_SELECTION_BROWSE:
+                 gtk_signal_emit (GTK_OBJECT (clist),
+                                  clist_signals[SELECT_ROW],
+                                  row, column, event);
+                 break;
+               case GTK_SELECTION_EXTENDED:
+                 if (event->type != GDK_BUTTON_PRESS)
+                   {
+                     if (clist->anchor != -1)
+                       {
+                         update_extended_selection (clist, clist->focus_row);
+                         GTK_CLIST_CLASS_FW (clist)->resync_selection
+                           (clist, (GdkEvent *) event);
+                       }
+                     gtk_signal_emit (GTK_OBJECT (clist),
+                                      clist_signals[SELECT_ROW],
+                                      row, column, event);
+                     break;
+                   }
+             
+                 if (event->state & GDK_CONTROL_MASK)
+                   {
+                     if (event->state & GDK_SHIFT_MASK)
+                       {
+                         if (clist->anchor < 0)
+                           {
+                             g_list_free (clist->undo_selection);
+                             g_list_free (clist->undo_unselection);
+                             clist->undo_selection = NULL;
+                             clist->undo_unselection = NULL;
+                             clist->anchor = old_row;
+                             clist->drag_pos = old_row;
+                             clist->undo_anchor = old_row;
+                           }
+                         update_extended_selection (clist, clist->focus_row);
+                       }
+                     else
+                       {
+                         if (clist->anchor == -1)
+                           set_anchor (clist, TRUE, row, old_row);
+                         else
+                           update_extended_selection (clist,
+                                                      clist->focus_row);
+                       }
+                     break;
+                   }
+
+                 if (event->state & GDK_SHIFT_MASK)
+                   {
+                     set_anchor (clist, FALSE, old_row, old_row);
+                     update_extended_selection (clist, clist->focus_row);
+                     break;
+                   }
+
+                 if (clist->anchor == -1)
+                   set_anchor (clist, FALSE, row, old_row);
+                 else
+                   update_extended_selection (clist, clist->focus_row);
+                 break;
+               default:
+                 break;
+               }
+           }
        }
-      break;
-    default:
-      break;
+      return FALSE;
     }
-}
 
-static void
-scroll_horizontal (GtkCList      *clist,
-                  GtkScrollType  scroll_type,
-                  gfloat         position)
-{
-  gint column = 0;
+  /* press on resize windows */
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].resizeable && clist->column[i].window &&
+       event->window == clist->column[i].window)
+      {
+       gpointer drag_data;
 
-  g_return_if_fail (clist != 0);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+       if (gdk_pointer_grab (clist->column[i].window, FALSE,
+                             GDK_POINTER_MOTION_HINT_MASK |
+                             GDK_BUTTON1_MOTION_MASK |
+                             GDK_BUTTON_RELEASE_MASK,
+                             NULL, NULL, event->time))
+         return FALSE;
 
-  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
-    return;
+       gtk_grab_add (widget);
+       GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
 
-  switch (scroll_type)
-    {
-    case GTK_SCROLL_STEP_BACKWARD:
-      column = COLUMN_FROM_XPIXEL (clist, 0);
-      if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
-         && column > 0)
-       column--;
-      break;
-    case GTK_SCROLL_STEP_FORWARD:
-      column =  COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
-      if (column < 0)
-       return;
-      if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
-         + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
-         column < clist->columns - 1)
-       column++;
-      break;
-    case GTK_SCROLL_PAGE_BACKWARD:
-    case GTK_SCROLL_PAGE_FORWARD:
-      return;
-    case GTK_SCROLL_JUMP:
-      if (position >= 0 && position <= 1)
-       column = position * (clist->columns - 1);
-      else
-       return;
-      break;
-    default:
-      break;
-    }
+       /* block attached dnd signal handler */
+       drag_data = gtk_object_get_data (GTK_OBJECT (clist), "gtk-site-data");
+       if (drag_data)
+         gtk_signal_handler_block_by_data (GTK_OBJECT (clist), drag_data);
 
-  if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
-    gtk_clist_moveto (clist, -1, column, 0, 0);
-  else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
-          + clist->column[column].area.width > clist->clist_window_width)
-    {
-      if (column == clist->columns - 1)
-       gtk_clist_moveto (clist, -1, column, 0, 0);
-      else
-       gtk_clist_moveto (clist, -1, column, 0, 1);
-    }
+       if (!GTK_WIDGET_HAS_FOCUS(widget))
+         gtk_widget_grab_focus (widget);
+
+       clist->drag_pos = i;
+       clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
+                        clist->column[i].area.width + CELL_SPACING);
+
+       if (GTK_CLIST_ADD_MODE(clist))
+         gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
+       draw_xor_line (clist);
+      }
+  return FALSE;
 }
 
-static void
-scroll_vertical (GtkCList      *clist,
-                GtkScrollType  scroll_type,
-                gfloat         position)
+static gint
+gtk_clist_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
 {
-  gint old_focus_row;
+  GtkCList *clist;
+  gint button_actions;
 
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (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 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
-    return;
+  clist = GTK_CLIST (widget);
 
-  switch (clist->selection_mode)
+  button_actions = clist->button_actions[event->button - 1];
+  if (button_actions == GTK_BUTTON_IGNORED)
+    return FALSE;
+
+  /* release on resize windows */
+  if (GTK_CLIST_IN_DRAG(clist))
     {
-    case GTK_SELECTION_EXTENDED:
-      if (clist->anchor >= 0)
-       return;
+      gpointer drag_data;
+      gint width;
+      gint x;
+      gint i;
 
-    case GTK_SELECTION_BROWSE:
+      i = clist->drag_pos;
+      clist->drag_pos = -1;
 
-      old_focus_row = clist->focus_row;
-      move_focus_row (clist, scroll_type, position);
+      /* unblock attached dnd signal handler */
+      drag_data = gtk_object_get_data (GTK_OBJECT (clist), "gtk-site-data");
+      if (drag_data)
+       gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), drag_data);
 
-      if (old_focus_row != clist->focus_row)
+      GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
+      gtk_widget_get_pointer (widget, &x, NULL);
+      gtk_grab_remove (widget);
+      gdk_pointer_ungrab (event->time);
+
+      if (clist->x_drag >= 0)
+       draw_xor_line (clist);
+
+      if (GTK_CLIST_ADD_MODE(clist))
        {
-         if (clist->selection_mode == GTK_SELECTION_BROWSE)
-           unselect_row (clist,old_focus_row, -1, NULL);
-         else if (!GTK_CLIST_ADD_MODE (clist))
-           {
-             gtk_clist_unselect_all (clist);
-             clist->undo_anchor = old_focus_row;
-           }
+         gdk_gc_set_line_attributes (clist->xor_gc, 1,
+                                     GDK_LINE_ON_OFF_DASH, 0, 0);
+         gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
        }
 
-      switch (gtk_clist_row_is_visible (clist, clist->focus_row))
-       {
-       case GTK_VISIBILITY_NONE:
-         if (old_focus_row != clist->focus_row &&
-             !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
-               GTK_CLIST_ADD_MODE (clist)))
-           select_row (clist, clist->focus_row, -1, NULL);
-         switch (scroll_type)
-           {
-           case GTK_SCROLL_STEP_BACKWARD:
-           case GTK_SCROLL_PAGE_BACKWARD:
-             gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
-             break;
-           case GTK_SCROLL_STEP_FORWARD:
-           case GTK_SCROLL_PAGE_FORWARD:
-             gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
-             break;
-           case GTK_SCROLL_JUMP:
-             gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
-             break;
-           default:
-             break;
-           }
-         break;
+      width = new_column_width (clist, i, &x);
+      gtk_clist_set_column_width (clist, i, width);
+      return FALSE;
+    }
 
-       case GTK_VISIBILITY_PARTIAL:
-         switch (scroll_type)
+  if (clist->drag_button == event->button)
+    {
+      gint row;
+      gint column;
+
+      clist->drag_button = 0;
+      clist->click_cell.row = -1;
+      clist->click_cell.column = -1;
+
+      remove_grab (clist);
+
+      if (button_actions & GTK_BUTTON_SELECTS)
+       {
+         switch (clist->selection_mode)
            {
-           case GTK_SCROLL_STEP_BACKWARD:
-           case GTK_SCROLL_PAGE_BACKWARD:
-             gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
-             break;
-           case GTK_SCROLL_STEP_FORWARD:
-           case GTK_SCROLL_PAGE_FORWARD:
-             gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+           case GTK_SELECTION_EXTENDED:
+             if (!(event->state & GDK_SHIFT_MASK) ||
+                 !GTK_WIDGET_CAN_FOCUS (widget) ||
+                 event->x < 0 || event->x >= clist->clist_window_width ||
+                 event->y < 0 || event->y >= clist->clist_window_height)
+               GTK_CLIST_CLASS_FW (clist)->resync_selection
+                 (clist, (GdkEvent *) event);
              break;
-           case GTK_SCROLL_JUMP:
-             gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
+           case GTK_SELECTION_SINGLE:
+           case GTK_SELECTION_MULTIPLE:
+             if (get_selection_info (clist, event->x, event->y,
+                                     &row, &column))
+               {
+                 if (row >= 0 && row < clist->rows && clist->anchor == row)
+                   toggle_row (clist, row, column, (GdkEvent *) event);
+               }
+             clist->anchor = -1;
              break;
            default:
              break;
            }
-
-       default:
-         if (old_focus_row != clist->focus_row &&
-             !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
-               GTK_CLIST_ADD_MODE (clist)))
-           select_row (clist, clist->focus_row, -1, NULL);
-         break;
        }
-      break;
-
-    default:
-      move_focus_row (clist, scroll_type, position);
-
-      if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
-         clist->clist_window_height)
-       gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
-      else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
-       gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
-      break;
     }
+  return FALSE;
 }
 
-static void
-set_anchor (GtkCList *clist,
-           gboolean  add_mode,
-           gint      anchor,
-           gint      undo_anchor)
+static gint
+gtk_clist_motion (GtkWidget      *widget,
+                 GdkEventMotion *event)
 {
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-  
-  if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
-    return;
-
-  g_list_free (clist->undo_selection);
-  g_list_free (clist->undo_unselection);
-  clist->undo_selection = NULL;
-  clist->undo_unselection = NULL;
+  GtkCList *clist;
+  gint x;
+  gint y;
+  gint row;
+  gint new_width;
+  gint button_actions = 0;
 
-  if (add_mode)
-    fake_toggle_row (clist, anchor);
-  else
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
+
+  clist = GTK_CLIST (widget);
+  if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
+    return FALSE;
+
+  if (clist->drag_button > 0)
+    button_actions = clist->button_actions[clist->drag_button - 1];
+
+  if (GTK_CLIST_IN_DRAG(clist))
     {
-      GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
-      clist->anchor_state = GTK_STATE_SELECTED;
+      if (event->is_hint || event->window != widget->window)
+       gtk_widget_get_pointer (widget, &x, NULL);
+      else
+       x = event->x;
+      
+      new_width = new_column_width (clist, clist->drag_pos, &x);
+      if (x != clist->x_drag)
+       {
+         /* x_drag < 0 indicates that the xor line is already invisible */
+         if (clist->x_drag >= 0)
+           draw_xor_line (clist);
+
+         clist->x_drag = x;
+
+         if (clist->x_drag >= 0)
+           draw_xor_line (clist);
+       }
+
+      if (new_width <= MAX (COLUMN_MIN_WIDTH + 1,
+                           clist->column[clist->drag_pos].min_width + 1))
+       {
+         if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0)
+           gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
+         return FALSE;
+       }
+      if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH &&
+         new_width >= clist->column[clist->drag_pos].max_width)
+       {
+         if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width >
+             clist->clist_window_width && x < 0)
+           move_horizontal (clist,
+                            COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) +
+                            new_width - clist->clist_window_width +
+                            COLUMN_INSET + CELL_SPACING);
+         return FALSE;
+       }
     }
 
-  clist->anchor = anchor;
-  clist->drag_pos = anchor;
-  clist->undo_anchor = undo_anchor;
-}
+  if (event->is_hint || event->window != clist->clist_window)
+    gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
 
-static void
-resync_selection (GtkCList *clist,
-                 GdkEvent *event)
-{
-  gint i;
-  gint e;
-  gint row;
-  gboolean thaw = FALSE;
-  GList *list;
-  GtkCListRow *clist_row;
+  if (GTK_CLIST_REORDERABLE(clist) && button_actions & GTK_BUTTON_DRAGS)
+    {
+      /* delayed drag start */
+      if (event->window == clist->clist_window &&
+         clist->click_cell.row >= 0 && clist->click_cell.column >= 0 &&
+         (y < 0 || y >= clist->clist_window_height ||
+          x < 0 || x >= clist->clist_window_width  ||
+          y < ROW_TOP_YPIXEL (clist, clist->click_cell.row) ||
+          y >= (ROW_TOP_YPIXEL (clist, clist->click_cell.row) +
+                clist->row_height) ||
+          x < COLUMN_LEFT_XPIXEL (clist, clist->click_cell.column) ||
+          x >= (COLUMN_LEFT_XPIXEL(clist, clist->click_cell.column) + 
+                clist->column[clist->click_cell.column].area.width)))
+       {
+         GtkTargetList  *target_list;
 
-  if (clist->anchor < 0)
-    return;
+         target_list = gtk_target_list_new (&clist_target_table, 1);
+         gtk_drag_begin (widget, target_list, GDK_ACTION_MOVE,
+                         clist->drag_button, (GdkEvent *)event);
 
-  if (!GTK_CLIST_FROZEN (clist))
-    {
-      GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
-      thaw = TRUE;
+       }
+      return TRUE;
     }
 
-  i = MIN (clist->anchor, clist->drag_pos);
-  e = MAX (clist->anchor, clist->drag_pos);
-
-  if (clist->undo_selection)
+  /* horizontal autoscrolling */
+  if (clist->hadjustment && LIST_WIDTH (clist) > clist->clist_window_width &&
+      (x < 0 || x >= clist->clist_window_width))
     {
-      list = clist->selection;
-      clist->selection = clist->undo_selection;
-      clist->selection_end = g_list_last (clist->selection);
-      clist->undo_selection = list;
-      list = clist->selection;
-      while (list)
+      if (clist->htimer)
+       return FALSE;
+
+      clist->htimer = gtk_timeout_add
+       (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
+
+      if (!((x < 0 && clist->hadjustment->value == 0) ||
+           (x >= clist->clist_window_width &&
+            clist->hadjustment->value ==
+            LIST_WIDTH (clist) - clist->clist_window_width)))
        {
-         row = GPOINTER_TO_INT (list->data);
-         list = list->next;
-         if (row < i || row > e)
-           {
-             clist_row = g_list_nth (clist->row_list, row)->data;
-             if (clist_row->selectable)
-               {
-                 clist_row->state = GTK_STATE_SELECTED;
-                 unselect_row (clist, row, -1, event);
-                 clist->undo_selection = g_list_prepend
-                   (clist->undo_selection, GINT_TO_POINTER (row));
-               }
-           }
+         if (x < 0)
+           move_horizontal (clist, -1 + (x/2));
+         else
+           move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
        }
-    }    
+    }
 
-  for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
-    if (GTK_CLIST_ROW (list)->selectable)
-      {
-       if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
-         {
-           if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
-             {
-               GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
-               unselect_row (clist, i, -1, event);
-               clist->undo_selection = g_list_prepend (clist->undo_selection,
-                                                       GINT_TO_POINTER (i));
-             }
-         }
-       else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
-         {
-           GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
-           clist->undo_unselection = g_list_prepend (clist->undo_unselection,
-                                                     GINT_TO_POINTER (i));
-         }
-      }
+  if (GTK_CLIST_IN_DRAG(clist))
+    return FALSE;
 
-  for (list = clist->undo_unselection; list; list = list->next)
-    gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
-                    GPOINTER_TO_INT (list->data), -1, event);
+  /* vertical autoscrolling */
+  row = ROW_FROM_YPIXEL (clist, y);
 
-  clist->anchor = -1;
-  clist->drag_pos = -1;
+  /* don't scroll on last pixel row if it's a cell spacing */
+  if (y == clist->clist_window_height - 1 &&
+      y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
+    return FALSE;
 
-  if (thaw)
-    GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
-}
+  if (LIST_HEIGHT (clist) > clist->clist_window_height &&
+      (y < 0 || y >= clist->clist_window_height))
+    {
+      if (clist->vtimer)
+       return FALSE;
 
-static void
-update_extended_selection (GtkCList *clist,
-                          gint      row)
-{
-  gint i;
-  GList *list;
-  GdkRectangle area;
-  gint s1 = -1;
-  gint s2 = -1;
-  gint e1 = -1;
-  gint e2 = -1;
-  gint y1 = clist->clist_window_height;
-  gint y2 = clist->clist_window_height;
-  gint h1 = 0;
-  gint h2 = 0;
-  gint top;
+      clist->vtimer = gtk_timeout_add (SCROLL_TIME,
+                                      (GtkFunction) vertical_timeout, clist);
 
-  if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
-    return;
+      if (clist->drag_button &&
+         ((y < 0 && clist->focus_row == 0) ||
+          (y >= clist->clist_window_height &&
+           clist->focus_row == clist->rows - 1)))
+       return FALSE;
+    }
 
-  if (row < 0)
-    row = 0;
-  if (row >= clist->rows)
-    row = clist->rows - 1;
+  row = CLAMP (row, 0, clist->rows - 1);
 
-  /* extending downwards */
-  if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
-    {
-      s2 = clist->drag_pos + 1;
-      e2 = row;
-    }
-  /* extending upwards */
-  else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
-    {
-      s2 = row;
-      e2 = clist->drag_pos - 1;
-    }
-  else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
-    {
-      e1 = clist->drag_pos;
-      /* row and drag_pos on different sides of anchor :
-        take back the selection between anchor and drag_pos,
-         select between anchor and row */
-      if (row < clist->anchor)
-       {
-         s1 = clist->anchor + 1;
-         s2 = row;
-         e2 = clist->anchor - 1;
-       }
-      /* take back the selection between anchor and drag_pos */
-      else
-       s1 = row + 1;
-    }
-  else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
+  if (button_actions & GTK_BUTTON_SELECTS &
+      !gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"))
     {
-      s1 = clist->drag_pos;
-      /* row and drag_pos on different sides of anchor :
-        take back the selection between anchor and drag_pos,
-         select between anchor and row */
-      if (row > clist->anchor)
+      if (row == clist->focus_row)
+       return FALSE;
+
+      gtk_clist_draw_focus (widget);
+      clist->focus_row = row;
+      gtk_clist_draw_focus (widget);
+
+      switch (clist->selection_mode)
        {
-         e1 = clist->anchor - 1;
-         s2 = clist->anchor + 1;
-         e2 = row;
+       case GTK_SELECTION_BROWSE:
+         gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                          clist->focus_row, -1, event);
+         break;
+       case GTK_SELECTION_EXTENDED:
+         update_extended_selection (clist, clist->focus_row);
+         break;
+       default:
+         break;
        }
-      /* take back the selection between anchor and drag_pos */
-      else
-       e1 = row - 1;
     }
+  
+  if (ROW_TOP_YPIXEL(clist, row) < 0)
+    move_vertical (clist, row, 0);
+  else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
+          clist->clist_window_height)
+    move_vertical (clist, row, 1);
 
-  clist->drag_pos = row;
+  return FALSE;
+}
 
-  area.x = 0;
-  area.width = clist->clist_window_width;
+static void
+gtk_clist_size_request (GtkWidget      *widget,
+                       GtkRequisition *requisition)
+{
+  GtkCList *clist;
+  gint i;
 
-  /* restore the elements between s1 and e1 */
-  if (s1 >= 0)
-    {
-      for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
-          i++, list = list->next)
-       if (GTK_CLIST_ROW (list)->selectable)
-         {
-           if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
-             GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
-           else
-             GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
-         }
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (requisition != NULL);
 
-      top = ROW_TOP_YPIXEL (clist, clist->focus_row);
+  clist = GTK_CLIST (widget);
 
-      if (top + clist->row_height <= 0)
-       {
-         area.y = 0;
-         area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
-         draw_rows (clist, &area);
-         gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+  requisition->width = 0;
+  requisition->height = 0;
+
+  /* compute the size of the column title (title) area */
+  clist->column_title_area.height = 0;
+  if (GTK_CLIST_SHOW_TITLES(clist))
+    for (i = 0; i < clist->columns; i++)
+      if (clist->column[i].button)
+       {
+         GtkRequisition child_requisition;
+         
+         gtk_widget_size_request (clist->column[i].button,
+                                  &child_requisition);
+         clist->column_title_area.height =
+           MAX (clist->column_title_area.height,
+                child_requisition.height);
+       }
+
+  requisition->width += (widget->style->klass->xthickness +
+                        GTK_CONTAINER (widget)->border_width) * 2;
+  requisition->height += (clist->column_title_area.height +
+                         (widget->style->klass->ythickness +
+                          GTK_CONTAINER (widget)->border_width) * 2);
+
+  /* if (!clist->hadjustment) */
+  requisition->width += list_requisition_width (clist);
+  /* if (!clist->vadjustment) */
+  requisition->height += LIST_HEIGHT (clist);
+}
+
+static void
+gtk_clist_size_allocate (GtkWidget     *widget,
+                        GtkAllocation *allocation)
+{
+  GtkCList *clist;
+  GtkAllocation clist_allocation;
+  gint border_width;
+
+  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;
+  border_width = GTK_CONTAINER (widget)->border_width;
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_move_resize (widget->window,
+                             allocation->x + border_width,
+                             allocation->y + border_width,
+                             allocation->width - border_width * 2,
+                             allocation->height - border_width * 2);
+    }
+
+  /* use internal allocation structure for all the math
+   * because it's easier than always subtracting the container
+   * border width */
+  clist->internal_allocation.x = 0;
+  clist->internal_allocation.y = 0;
+  clist->internal_allocation.width = MAX (1, (gint)allocation->width -
+                                         border_width * 2);
+  clist->internal_allocation.height = MAX (1, (gint)allocation->height -
+                                          border_width * 2);
+       
+  /* allocate clist window assuming no scrollbars */
+  clist_allocation.x = (clist->internal_allocation.x +
+                       widget->style->klass->xthickness);
+  clist_allocation.y = (clist->internal_allocation.y +
+                       widget->style->klass->ythickness +
+                       clist->column_title_area.height);
+  clist_allocation.width = MAX (1, (gint)clist->internal_allocation.width - 
+                               (2 * (gint)widget->style->klass->xthickness));
+  clist_allocation.height = MAX (1, (gint)clist->internal_allocation.height -
+                                (2 * (gint)widget->style->klass->ythickness) -
+                                (gint)clist->column_title_area.height);
+  
+  clist->clist_window_width = clist_allocation.width;
+  clist->clist_window_height = clist_allocation.height;
+  
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      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 = widget->style->klass->xthickness;
+  clist->column_title_area.y = widget->style->klass->ythickness;
+  clist->column_title_area.width = clist_allocation.width;
+  
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_move_resize (clist->title_window,
+                             clist->column_title_area.x,
+                             clist->column_title_area.y,
+                             clist->column_title_area.width,
+                             clist->column_title_area.height);
+    }
+  
+  /* column button allocation */
+  size_allocate_columns (clist, FALSE);
+  size_allocate_title_buttons (clist);
+
+  adjust_adjustments (clist, TRUE);
+}
+
+/* GTKCONTAINER
+ *   gtk_clist_forall
+ */
+static void
+gtk_clist_forall (GtkContainer *container,
+                 gboolean      include_internals,
+                 GtkCallback   callback,
+                 gpointer      callback_data)
+{
+  GtkCList *clist;
+  guint i;
+
+  g_return_if_fail (container != NULL);
+  g_return_if_fail (GTK_IS_CLIST (container));
+  g_return_if_fail (callback != NULL);
+
+  if (!include_internals)
+    return;
+
+  clist = GTK_CLIST (container);
+      
+  /* callback for the column buttons */
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].button)
+      (*callback) (clist->column[i].button, callback_data);
+}
+
+/* PRIVATE DRAWING FUNCTIONS
+ *   get_cell_style
+ *   draw_cell_pixmap
+ *   draw_row
+ *   draw_rows
+ *   draw_xor_line
+ *   clist_refresh
+ */
+static void
+get_cell_style (GtkCList     *clist,
+               GtkCListRow  *clist_row,
+               gint          state,
+               gint          column,
+               GtkStyle    **style,
+               GdkGC       **fg_gc,
+               GdkGC       **bg_gc)
+{
+  gint fg_state;
+
+  if ((state == GTK_STATE_NORMAL) &&
+      (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE))
+    fg_state = GTK_STATE_INSENSITIVE;
+  else
+    fg_state = state;
+
+  if (clist_row->cell[column].style)
+    {
+      if (style)
+       *style = clist_row->cell[column].style;
+      if (fg_gc)
+       *fg_gc = clist_row->cell[column].style->fg_gc[fg_state];
+      if (bg_gc) {
+       if (state == GTK_STATE_SELECTED)
+         *bg_gc = clist_row->cell[column].style->bg_gc[state];
+       else
+         *bg_gc = clist_row->cell[column].style->base_gc[state];
+      }
+    }
+  else if (clist_row->style)
+    {
+      if (style)
+       *style = clist_row->style;
+      if (fg_gc)
+       *fg_gc = clist_row->style->fg_gc[fg_state];
+      if (bg_gc) {
+       if (state == GTK_STATE_SELECTED)
+         *bg_gc = clist_row->style->bg_gc[state];
+       else
+         *bg_gc = clist_row->style->base_gc[state];
+      }
+    }
+  else
+    {
+      if (style)
+       *style = GTK_WIDGET (clist)->style;
+      if (fg_gc)
+       *fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state];
+      if (bg_gc) {
+       if (state == GTK_STATE_SELECTED)
+         *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
+       else
+         *bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
+      }
+
+      if (state != GTK_STATE_SELECTED)
+       {
+         if (fg_gc && clist_row->fg_set)
+           *fg_gc = clist->fg_gc;
+         if (bg_gc && clist_row->bg_set)
+           *bg_gc = clist->bg_gc;
+       }
+    }
+}
+
+static gint
+draw_cell_pixmap (GdkWindow    *window,
+                 GdkRectangle *clip_rectangle,
+                 GdkGC        *fg_gc,
+                 GdkPixmap    *pixmap,
+                 GdkBitmap    *mask,
+                 gint          x,
+                 gint          y,
+                 gint          width,
+                 gint          height)
+{
+  gint xsrc = 0;
+  gint ysrc = 0;
+
+  if (mask)
+    {
+      gdk_gc_set_clip_mask (fg_gc, mask);
+      gdk_gc_set_clip_origin (fg_gc, x, y);
+    }
+
+  if (x < clip_rectangle->x)
+    {
+      xsrc = clip_rectangle->x - x;
+      width -= xsrc;
+      x = clip_rectangle->x;
+    }
+  if (x + width > clip_rectangle->x + clip_rectangle->width)
+    width = clip_rectangle->x + clip_rectangle->width - x;
+
+  if (y < clip_rectangle->y)
+    {
+      ysrc = clip_rectangle->y - y;
+      height -= ysrc;
+      y = clip_rectangle->y;
+    }
+  if (y + height > clip_rectangle->y + clip_rectangle->height)
+    height = clip_rectangle->y + clip_rectangle->height - y;
+
+  gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
+  gdk_gc_set_clip_origin (fg_gc, 0, 0);
+  if (mask)
+    gdk_gc_set_clip_mask (fg_gc, NULL);
+
+  return x + MAX (width, 0);
+}
+
+static void
+draw_row (GtkCList     *clist,
+         GdkRectangle *area,
+         gint          row,
+         GtkCListRow  *clist_row)
+{
+  GtkWidget *widget;
+  GdkRectangle *rect;
+  GdkRectangle row_rectangle;
+  GdkRectangle cell_rectangle;
+  GdkRectangle clip_rectangle;
+  GdkRectangle intersect_rectangle;
+  gint last_column;
+  gint state;
+  gint i;
+
+  g_return_if_fail (clist != NULL);
+
+  /* bail now if we arn't drawable yet */
+  if (!GTK_WIDGET_DRAWABLE (clist) || 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 = ROW_ELEMENT (clist, 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, its 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;
+
+  if (clist_row->state == GTK_STATE_NORMAL)
+    {
+      if (clist_row->fg_set)
+       gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
+      if (clist_row->bg_set)
+       gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
+    }
+
+  state = clist_row->state;
+
+  /* draw the cell borders and background */
+  if (area)
+    {
+      rect = &intersect_rectangle;
+      if (gdk_rectangle_intersect (area, &cell_rectangle,
+                                  &intersect_rectangle))
+       gdk_draw_rectangle (clist->clist_window,
+                           widget->style->base_gc[GTK_STATE_ACTIVE],
+                           TRUE,
+                           intersect_rectangle.x,
+                           intersect_rectangle.y,
+                           intersect_rectangle.width,
+                           intersect_rectangle.height);
+
+      /* the last row has to clear its 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_draw_rectangle (clist->clist_window,
+                               widget->style->base_gc[GTK_STATE_ACTIVE],
+                               TRUE,
+                               intersect_rectangle.x,
+                               intersect_rectangle.y,
+                               intersect_rectangle.width,
+                               intersect_rectangle.height);
+       }
+
+      if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle))
+       return;
+
+    }
+  else
+    {
+      rect = &clip_rectangle;
+      gdk_draw_rectangle (clist->clist_window,
+                         widget->style->base_gc[GTK_STATE_ACTIVE],
+                         TRUE,
+                         cell_rectangle.x,
+                         cell_rectangle.y,
+                         cell_rectangle.width,
+                         cell_rectangle.height);
+
+      /* the last row has to clear its bottom cell spacing too */
+      if (clist_row == clist->row_list_end->data)
+       {
+         cell_rectangle.y += clist->row_height + CELL_SPACING;
+
+         gdk_draw_rectangle (clist->clist_window,
+                             widget->style->base_gc[GTK_STATE_ACTIVE],
+                             TRUE,
+                             cell_rectangle.x,
+                             cell_rectangle.y,
+                             cell_rectangle.width,
+                             cell_rectangle.height);     
+       }         
+    }
+  
+  for (last_column = clist->columns - 1;
+       last_column >= 0 && !clist->column[last_column].visible; last_column--)
+    ;
+
+  /* iterate and draw all the columns (row cells) and draw their contents */
+  for (i = 0; i < clist->columns; i++)
+    {
+      GtkStyle *style;
+      GdkGC *fg_gc;
+      GdkGC *bg_gc;
+
+      gint width;
+      gint height;
+      gint pixmap_width;
+      gint offset = 0;
+      gint row_center_offset;
+
+      if (!clist->column[i].visible)
+       continue;
+
+      get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc);
+
+      clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
+      clip_rectangle.width = clist->column[i].area.width;
+
+      /* calculate clipping region clipping region */
+      clip_rectangle.x -= COLUMN_INSET + CELL_SPACING;
+      clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING +
+                              (i == last_column) * CELL_SPACING);
+      
+      if (area && !gdk_rectangle_intersect (area, &clip_rectangle,
+                                           &intersect_rectangle))
+       continue;
+
+      gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
+                         rect->x, rect->y, rect->width, rect->height);
+
+      clip_rectangle.x += COLUMN_INSET + CELL_SPACING;
+      clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING +
+                              (i == last_column) * CELL_SPACING);
+
+      /* calculate real width for column justification */
+      pixmap_width = 0;
+      offset = 0;
+      switch (clist_row->cell[i].type)
+       {
+       case GTK_CELL_TEXT:
+         width = gdk_string_width (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,
+                              &pixmap_width, &height);
+         width = pixmap_width;
+         break;
+       case GTK_CELL_PIXTEXT:
+         gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
+                              &pixmap_width, &height);
+         width = (pixmap_width +
+                  GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing +
+                  gdk_string_width (style->font,
+                                    GTK_CELL_PIXTEXT
+                                    (clist_row->cell[i])->text));
+         break;
+       default:
+         continue;
+         break;
+       }
+
+      switch (clist->column[i].justification)
+       {
+       case GTK_JUSTIFY_LEFT:
+         offset = clip_rectangle.x + clist_row->cell[i].horizontal;
+         break;
+       case GTK_JUSTIFY_RIGHT:
+         offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
+                   clip_rectangle.width - width);
+         break;
+       case GTK_JUSTIFY_CENTER:
+       case GTK_JUSTIFY_FILL:
+         offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
+                   (clip_rectangle.width / 2) - (width / 2));
+         break;
+       };
+
+      /* Draw Text and/or Pixmap */
+      switch (clist_row->cell[i].type)
+       {
+       case GTK_CELL_PIXMAP:
+         draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
+                           GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
+                           GTK_CELL_PIXMAP (clist_row->cell[i])->mask,
+                           offset,
+                           clip_rectangle.y + clist_row->cell[i].vertical +
+                           (clip_rectangle.height - height) / 2,
+                           pixmap_width, height);
+         break;
+       case GTK_CELL_PIXTEXT:
+         offset =
+           draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
+                             GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
+                             GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
+                             offset,
+                             clip_rectangle.y + clist_row->cell[i].vertical+
+                             (clip_rectangle.height - height) / 2,
+                             pixmap_width, height);
+         offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
+       case GTK_CELL_TEXT:
+         if (style != GTK_WIDGET (clist)->style)
+           row_center_offset = (((clist->row_height - style->font->ascent -
+                                 style->font->descent - 1) / 2) + 1.5 +
+                                style->font->ascent);
+         else
+           row_center_offset = clist->row_center_offset;
+
+         gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
+         gdk_draw_string (clist->clist_window, style->font, fg_gc,
+                          offset,
+                          row_rectangle.y + row_center_offset + 
+                          clist_row->cell[i].vertical,
+                          (clist_row->cell[i].type == GTK_CELL_PIXTEXT) ?
+                          GTK_CELL_PIXTEXT (clist_row->cell[i])->text :
+                          GTK_CELL_TEXT (clist_row->cell[i])->text);
+         gdk_gc_set_clip_rectangle (fg_gc, NULL);
+         break;
+       default:
+         break;
+       }
+    }
+
+  /* draw focus rectangle */
+  if (clist->focus_row == row &&
+      GTK_WIDGET_CAN_FOCUS (widget) && GTK_WIDGET_HAS_FOCUS(widget))
+    {
+      if (!area)
+       gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
+                           row_rectangle.x, row_rectangle.y,
+                           row_rectangle.width - 1, row_rectangle.height - 1);
+      else if (gdk_rectangle_intersect (area, &row_rectangle,
+                                       &intersect_rectangle))
+       {
+         gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
+         gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
+                             row_rectangle.x, row_rectangle.y,
+                             row_rectangle.width - 1,
+                             row_rectangle.height - 1);
+         gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
+       }
+    }
+}
+
+static void
+draw_rows (GtkCList     *clist,
+          GdkRectangle *area)
+{
+  GList *list;
+  GtkCListRow *clist_row;
+  gint i;
+  gint first_row;
+  gint last_row;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (clist->row_height == 0 ||
+      !GTK_WIDGET_DRAWABLE (clist))
+    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);
+    }
+
+  /* this is a small special case which exposes the bottom cell line
+   * on the last row -- it might go away if I change the wall the cell
+   * spacings are drawn
+   */
+  if (clist->rows == first_row)
+    first_row--;
+
+  list = ROW_ELEMENT (clist, first_row);
+  i = first_row;
+  while (list)
+    {
+      clist_row = list->data;
+      list = list->next;
+
+      if (i > last_row)
+       return;
+
+      GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
+      i++;
+    }
+
+  if (!area)
+    gdk_window_clear_area (clist->clist_window, 0,
+                          ROW_TOP_YPIXEL (clist, i), 0, 0);
+}
+
+static void                          
+draw_xor_line (GtkCList *clist)
+{
+  GtkWidget *widget;
+
+  g_return_if_fail (clist != NULL);
+
+  widget = GTK_WIDGET (clist);
+
+  gdk_draw_line (widget->window, clist->xor_gc,
+                 clist->x_drag,
+                widget->style->klass->ythickness,
+                 clist->x_drag,
+                 clist->column_title_area.height +
+                clist->clist_window_height + 1);
+}
+
+static void
+clist_refresh (GtkCList *clist)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  
+  if (CLIST_UNFROZEN (clist))
+    { 
+      adjust_adjustments (clist, FALSE);
+      draw_rows (clist, NULL);
+    }
+}
+
+/* get cell from coordinates
+ *   get_selection_info
+ *   gtk_clist_get_selection_info
+ */
+static gint
+get_selection_info (GtkCList *clist,
+                   gint      x,
+                   gint      y,
+                   gint     *row,
+                   gint     *column)
+{
+  gint trow, tcol;
+
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 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;
+}
+
+gint
+gtk_clist_get_selection_info (GtkCList *clist, 
+                             gint      x, 
+                             gint      y, 
+                             gint     *row, 
+                             gint     *column)
+{
+  g_return_val_if_fail (clist != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
+  return get_selection_info (clist, x, y, row, column);
+}
+
+/* PRIVATE ADJUSTMENT FUNCTIONS
+ *   adjust_adjustments
+ *   vadjustment_changed
+ *   hadjustment_changed
+ *   vadjustment_value_changed
+ *   hadjustment_value_changed 
+ *   check_exposures
+ */
+static void
+adjust_adjustments (GtkCList *clist,
+                   gboolean  block_resize)
+{
+  if (clist->vadjustment)
+    {
+      clist->vadjustment->page_size = clist->clist_window_height;
+      clist->vadjustment->page_increment = clist->clist_window_height / 2;
+      clist->vadjustment->step_increment = clist->row_height;
+      clist->vadjustment->lower = 0;
+      clist->vadjustment->upper = LIST_HEIGHT (clist);
+
+      if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist) ||
+         (clist->voffset + (gint)clist->vadjustment->value) != 0)
+       {
+         clist->vadjustment->value = MAX (0, (LIST_HEIGHT (clist) -
+                                              clist->clist_window_height));
+         gtk_signal_emit_by_name (GTK_OBJECT (clist->vadjustment),
+                                  "value_changed");
+       }
+      gtk_signal_emit_by_name (GTK_OBJECT (clist->vadjustment), "changed");
+    }
+
+  if (clist->hadjustment)
+    {
+      clist->hadjustment->page_size = clist->clist_window_width;
+      clist->hadjustment->page_increment = clist->clist_window_width / 2;
+      clist->hadjustment->step_increment = 10;
+      clist->hadjustment->lower = 0;
+      clist->hadjustment->upper = LIST_WIDTH (clist);
+
+      if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist) ||
+         (clist->hoffset + (gint)clist->hadjustment->value) != 0)
+       {
+         clist->hadjustment->value = MAX (0, (LIST_WIDTH (clist) -
+                                              clist->clist_window_width));
+         gtk_signal_emit_by_name (GTK_OBJECT (clist->hadjustment),
+                                  "value_changed");
+       }
+      gtk_signal_emit_by_name (GTK_OBJECT (clist->hadjustment), "changed");
+    }
+
+  if (!block_resize && (!clist->vadjustment || !clist->hadjustment))
+    {
+      GtkWidget *widget;
+      GtkRequisition requisition;
+
+      widget = GTK_WIDGET (clist);
+      gtk_widget_size_request (widget, &requisition);
+
+      if ((!clist->hadjustment &&
+          requisition.width != widget->allocation.width) ||
+         (!clist->vadjustment &&
+          requisition.height != widget->allocation.height))
+       gtk_widget_queue_resize (widget);
+    }
+}
+
+static void
+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
+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
+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);
+
+  if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->vadjustment)
+    return;
+
+  value = adjustment->value;
+
+  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;
+         draw_rows (clist, NULL);
+         return;
+       }
+
+      if ((diff != 0) && (diff != clist->clist_window_height))
+       gdk_window_copy_area (clist->clist_window, clist->fg_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;
+         draw_rows (clist, NULL);
+         return;
+       }
+
+      if ((diff != 0) && (diff != clist->clist_window_height))
+       gdk_window_copy_area (clist->clist_window, clist->fg_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;
+  if ((diff != 0) && (diff != clist->clist_window_height))
+    check_exposures (clist);
+
+  draw_rows (clist, &area);
+}
+
+static void
+hadjustment_value_changed (GtkAdjustment *adjustment,
+                          gpointer       data)
+{
+  GtkCList *clist;
+  GdkRectangle area;
+  gint i;
+  gint y = 0;
+  gint diff = 0;
+  gint 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);
+
+  if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->hadjustment)
+    return;
+
+  value = adjustment->value;
+
+  /* move the column buttons and resize windows */
+  for (i = 0; i < clist->columns; i++)
+    {
+      if (clist->column[i].button)
+       {
+         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 (clist->column[i].window)
+               gdk_window_move (clist->column[i].window,
+                                clist->column[i].button->allocation.x +
+                                clist->column[i].button->allocation.width - 
+                                (DRAG_WIDTH / 2), 0); 
+           }
        }
-      else if (top >= clist->clist_window_height)
+    }
+
+  if (value > -clist->hoffset)
+    {
+      /* scroll right */
+      diff = value + clist->hoffset;
+      
+      clist->hoffset = -value;
+      
+      /* we have to re-draw the whole screen here... */
+      if (diff >= clist->clist_window_width)
        {
-         area.y = ROW_TOP_YPIXEL (clist, s1);
-         area.height = clist->clist_window_height - area.y;
+         draw_rows (clist, NULL);
+         return;
+       }
+
+      if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) &&
+         !GTK_CLIST_CHILD_HAS_FOCUS(clist) && GTK_CLIST_ADD_MODE(clist))
+       {
+         y = ROW_TOP_YPIXEL (clist, clist->focus_row);
+             
+         gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
+                             clist->clist_window_width - 1,
+                             clist->row_height - 1);
+       }
+      gdk_window_copy_area (clist->clist_window,
+                           clist->fg_gc,
+                           0, 0,
+                           clist->clist_window,
+                           diff,
+                           0,
+                           clist->clist_window_width - diff,
+                           clist->clist_window_height);
+
+      area.x = clist->clist_window_width - diff;
+    }
+  else
+    {
+      /* scroll left */
+      if (!(diff = -clist->hoffset - value))
+       return;
+
+      clist->hoffset = -value;
+      
+      /* we have to re-draw the whole screen here... */
+      if (diff >= clist->clist_window_width)
+       {
+         draw_rows (clist, NULL);
+         return;
+       }
+      
+      if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) &&
+         !GTK_CLIST_CHILD_HAS_FOCUS(clist) && GTK_CLIST_ADD_MODE(clist))
+       {
+         y = ROW_TOP_YPIXEL (clist, clist->focus_row);
+         
+         gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
+                             clist->clist_window_width - 1,
+                             clist->row_height - 1);
+       }
+
+      gdk_window_copy_area (clist->clist_window,
+                           clist->fg_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;
+
+  check_exposures (clist);
+
+  if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) &&
+      !GTK_CLIST_CHILD_HAS_FOCUS(clist))
+    {
+      if (GTK_CLIST_ADD_MODE(clist))
+       {
+         gint focus_row;
+         
+         focus_row = clist->focus_row;
+         clist->focus_row = -1;
          draw_rows (clist, &area);
-         gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+         clist->focus_row = focus_row;
+         
+         gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
+                             FALSE, 0, y, clist->clist_window_width - 1,
+                             clist->row_height - 1);
+         return;
        }
-      else if (top < 0)
-       gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
-      else if (top + clist->row_height > clist->clist_window_height)
-       gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+      else
+       {
+         gint x0;
+         gint x1;
+         
+         if (area.x == 0)
+           {
+             x0 = clist->clist_window_width - 1;
+             x1 = diff;
+           }
+         else
+           {
+             x0 = 0;
+             x1 = area.x - 1;
+           }
+         
+         y = ROW_TOP_YPIXEL (clist, clist->focus_row);
+         gdk_draw_line (clist->clist_window, clist->xor_gc,
+                        x0, y + 1, x0, y + clist->row_height - 2);
+         gdk_draw_line (clist->clist_window, clist->xor_gc,
+                        x1, y + 1, x1, y + clist->row_height - 2);
+         
+       }
+    }
+  draw_rows (clist, &area);
+}
 
-      y1 = ROW_TOP_YPIXEL (clist, s1);
-      h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
+static void
+check_exposures (GtkCList *clist)
+{
+  GdkEvent *event;
+
+  if (!GTK_WIDGET_REALIZED (clist))
+    return;
+
+  /* Make sure graphics expose events are processed before scrolling
+   * again */
+  while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
+    {
+      gtk_widget_event (GTK_WIDGET (clist), event);
+      if (event->expose.count == 0)
+       {
+         gdk_event_free (event);
+         break;
+       }
+      gdk_event_free (event);
+    }
+}
+
+/* PRIVATE 
+ * Memory Allocation/Distruction Routines for GtkCList stuctures
+ *
+ * functions:
+ *   columns_new
+ *   column_title_new
+ *   columns_delete
+ *   row_new
+ *   row_delete
+ */
+static GtkCListColumn *
+columns_new (GtkCList *clist)
+{
+  GtkCListColumn *column;
+  gint i;
+
+  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].window = NULL;
+      column[i].width = 0;
+      column[i].min_width = -1;
+      column[i].max_width = -1;
+      column[i].visible = TRUE;
+      column[i].width_set = FALSE;
+      column[i].resizeable = TRUE;
+      column[i].auto_resize = FALSE;
+      column[i].button_passive = FALSE;
+      column[i].justification = GTK_JUSTIFY_LEFT;
+    }
+
+  return column;
+}
+
+static void
+column_title_new (GtkCList    *clist,
+                 gint         column,
+                 const gchar *title)
+{
+  if (clist->column[column].title)
+    g_free (clist->column[column].title);
+
+  clist->column[column].title = g_strdup (title);
+}
+
+static void
+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 *
+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].vertical = 0;
+      clist_row->cell[i].horizontal = 0;
+      clist_row->cell[i].style = NULL;
     }
 
-  /* extend the selection between s2 and e2 */
-  if (s2 >= 0)
-    {
-      for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
-          i++, list = list->next)
-       if (GTK_CLIST_ROW (list)->selectable &&
-           GTK_CLIST_ROW (list)->state != clist->anchor_state)
-         GTK_CLIST_ROW (list)->state = clist->anchor_state;
+  clist_row->fg_set = FALSE;
+  clist_row->bg_set = FALSE;
+  clist_row->style = NULL;
+  clist_row->selectable = TRUE;
+  clist_row->state = GTK_STATE_NORMAL;
+  clist_row->data = NULL;
+  clist_row->destroy = NULL;
 
-      top = ROW_TOP_YPIXEL (clist, clist->focus_row);
+  return clist_row;
+}
 
-      if (top + clist->row_height <= 0)
-       {
-         area.y = 0;
-         area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
-         draw_rows (clist, &area);
-         gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
-       }
-      else if (top >= clist->clist_window_height)
+static void
+row_delete (GtkCList    *clist,
+           GtkCListRow *clist_row)
+{
+  gint i;
+
+  for (i = 0; i < clist->columns; i++)
+    {
+      GTK_CLIST_CLASS_FW (clist)->set_cell_contents
+       (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
+      if (clist_row->cell[i].style)
        {
-         area.y = ROW_TOP_YPIXEL (clist, s2);
-         area.height = clist->clist_window_height - area.y;
-         draw_rows (clist, &area);
-         gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+         if (GTK_WIDGET_REALIZED (clist))
+           gtk_style_detach (clist_row->cell[i].style);
+         gtk_style_unref (clist_row->cell[i].style);
        }
-      else if (top < 0)
-       gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
-      else if (top + clist->row_height > clist->clist_window_height)
-       gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+    }
 
-      y2 = ROW_TOP_YPIXEL (clist, s2);
-      h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
+  if (clist_row->style)
+    {
+      if (GTK_WIDGET_REALIZED (clist))
+        gtk_style_detach (clist_row->style);
+      gtk_style_unref (clist_row->style);
     }
 
-  area.y = MAX (0, MIN (y1, y2));
-  if (area.y > clist->clist_window_height)
-    area.y = 0;
-  area.height = MIN (clist->clist_window_height, h1 + h2);
-  if (s1 >= 0 && s2 >= 0)
-    area.height += (clist->row_height + CELL_SPACING);
-  draw_rows (clist, &area);
+  if (clist_row->destroy)
+    clist_row->destroy (clist_row->data);
+
+  g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
+  g_mem_chunk_free (clist->row_mem_chunk, clist_row);
 }
 
-static void
-start_selection (GtkCList *clist)
+/* FOCUS FUNCTIONS
+ *   gtk_clist_focus
+ *   gtk_clist_draw_focus
+ *   gtk_clist_focus_in
+ *   gtk_clist_focus_out
+ *   gtk_clist_set_focus_child
+ *   title_focus
+ */
+static gint
+gtk_clist_focus (GtkContainer     *container,
+                GtkDirectionType  direction)
 {
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  GtkCList *clist;
+  GtkWidget *focus_child;
+  gint old_row;
 
-  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
-    return;
+  g_return_val_if_fail (container != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
 
-  set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
-             clist->focus_row);
-}
+  if (!GTK_WIDGET_IS_SENSITIVE (container))
+    return FALSE;
+  
+  clist = GTK_CLIST (container);
+  focus_child = container->focus_child;
+  old_row = clist->focus_row;
 
-static void
-end_selection (GtkCList *clist)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  switch (direction)
+    {
+    case GTK_DIR_LEFT:
+    case GTK_DIR_RIGHT:
+      if (GTK_CLIST_CHILD_HAS_FOCUS(clist))
+       {
+         if (title_focus (clist, direction))
+           return TRUE;
+         gtk_container_set_focus_child (container, NULL);
+         return FALSE;
+        }
+      gtk_widget_grab_focus (GTK_WIDGET (container));
+      return TRUE;
+    case GTK_DIR_DOWN:
+    case GTK_DIR_TAB_FORWARD:
+      if (GTK_CLIST_CHILD_HAS_FOCUS(clist))
+       {
+         gboolean tf = FALSE;
 
-  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
-      clist->anchor == -1)
-    return;
-  
-  GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
-}
+         if (((focus_child && direction == GTK_DIR_DOWN) ||
+              !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
+             && clist->rows)
+           {
+             if (clist->focus_row < 0)
+               {
+                 clist->focus_row = 0;
 
-static void
-extend_selection (GtkCList      *clist,
-                 GtkScrollType  scroll_type,
-                 gfloat         position,
-                 gboolean       auto_start_selection)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+                 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
+                      clist->selection_mode == GTK_SELECTION_EXTENDED) &&
+                     !clist->selection)
+                   gtk_signal_emit (GTK_OBJECT (clist),
+                                    clist_signals[SELECT_ROW],
+                                    clist->focus_row, -1, NULL);
+               }
+             gtk_widget_grab_focus (GTK_WIDGET (container));
+             return TRUE;
+           }
 
-  if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
-      clist->selection_mode != GTK_SELECTION_EXTENDED)
-    return;
+         if (tf)
+           return TRUE;
+       }
+      
+      GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
+      break;
+    case GTK_DIR_UP:
+    case GTK_DIR_TAB_BACKWARD:
+      if (!focus_child &&
+         GTK_CLIST_CHILD_HAS_FOCUS(clist) && clist->rows)
+       {
+         if (clist->focus_row < 0)
+           {
+             clist->focus_row = 0;
+             if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
+                  clist->selection_mode == GTK_SELECTION_EXTENDED) &&
+                 !clist->selection)
+               gtk_signal_emit (GTK_OBJECT (clist),
+                                clist_signals[SELECT_ROW],
+                                clist->focus_row, -1, NULL);
+           }
+         gtk_widget_grab_focus (GTK_WIDGET (container));
+         return TRUE;
+       }
 
-  if (auto_start_selection)
-    set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
-               clist->focus_row);
-  else if (clist->anchor == -1)
-    return;
+      GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
 
-  move_focus_row (clist, scroll_type, position);
+      if (title_focus (clist, direction))
+       return TRUE;
 
-  if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
-      clist->clist_window_height)
-    gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
-  else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
-    gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+      break;
+    default:
+      break;
+    }
 
-  update_extended_selection (clist, clist->focus_row);
+  gtk_container_set_focus_child (container, NULL);
+  return FALSE;
 }
 
 static void
-abort_column_resize (GtkCList *clist)
+gtk_clist_draw_focus (GtkWidget *widget)
 {
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
 
-  if (!GTK_CLIST_IN_DRAG (clist))
+  if (!GTK_WIDGET_DRAWABLE (widget) || !GTK_WIDGET_CAN_FOCUS (widget))
     return;
 
-  GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
-  gtk_grab_remove (GTK_WIDGET (clist));
-  gdk_pointer_ungrab (GDK_CURRENT_TIME);
-  clist->drag_pos = -1;
+  clist = GTK_CLIST (widget);
+  if (clist->focus_row >= 0)
+    gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
+                       0, ROW_TOP_YPIXEL(clist, clist->focus_row),
+                       clist->clist_window_width - 1,
+                       clist->row_height - 1);
+}
 
-  if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
-    draw_xor_line (clist);
+static gint
+gtk_clist_focus_in (GtkWidget     *widget,
+                   GdkEventFocus *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);
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+  GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
+
+  clist = GTK_CLIST (widget);
 
-  if (GTK_CLIST_ADD_MODE (clist))
+  if (clist->selection_mode == GTK_SELECTION_BROWSE &&
+      clist->selection == NULL && clist->focus_row > -1)
     {
-      gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
-      gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
+      GList *list;
+
+      list = g_list_nth (clist->row_list, clist->focus_row);
+      if (list && GTK_CLIST_ROW (list)->selectable)
+       gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                        clist->focus_row, -1, event);
+      else
+       gtk_widget_draw_focus (widget);
     }
+  else
+    gtk_widget_draw_focus (widget);
+
+  return FALSE;
 }
 
 static gint
-gtk_clist_key_press (GtkWidget   * widget,
-                    GdkEventKey * event)
+gtk_clist_focus_out (GtkWidget     *widget,
+                    GdkEventFocus *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_CLASS (parent_class)->key_press_event &&
-      GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
-    return TRUE;
-
-  switch (event->keyval)
-    {
-    case GDK_Tab:
-    case GDK_ISO_Left_Tab:
-      if (event->state & GDK_SHIFT_MASK)
-       return gtk_container_focus (GTK_CONTAINER (widget),
-                                   GTK_DIR_TAB_BACKWARD);
-      else
-       return gtk_container_focus (GTK_CONTAINER (widget),
-                                   GTK_DIR_TAB_FORWARD);
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+  GTK_CLIST_SET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
 
-    default:
-      break;
-    }
+  gtk_widget_draw_focus (widget);
   
+  clist = GTK_CLIST (widget);
+
+  GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
+
   return FALSE;
 }
 
+static void
+gtk_clist_set_focus_child (GtkContainer *container,
+                          GtkWidget    *child)
+{
+  g_return_if_fail (container != NULL);
+  g_return_if_fail (GTK_IS_CLIST (container));
+
+  if (child)
+    {
+      g_return_if_fail (GTK_IS_WIDGET (child));
+      GTK_CLIST_SET_FLAG (container, CLIST_CHILD_HAS_FOCUS);
+    }
+
+  parent_class->set_focus_child (container, child);
+}
+
 static gboolean
-title_focus (GtkCList * clist,
-            gint       dir)
+title_focus (GtkCList *clist,
+            gint      dir)
 {
   GtkWidget *focus_child;
   gboolean return_val = FALSE;
+  gint last_column;
   gint d = 1;
   gint i = 0;
   gint j;
 
-  if (!GTK_CLIST_SHOW_TITLES (clist))
+  if (!GTK_CLIST_SHOW_TITLES(clist))
     return FALSE;
 
   focus_child = GTK_CONTAINER (clist)->focus_child;
+
+  for (last_column = clist->columns - 1;
+       last_column >= 0 && !clist->column[last_column].visible; last_column--)
+    ;
   
   switch (dir)
     {
     case GTK_DIR_TAB_BACKWARD:
     case GTK_DIR_UP:
-      if (!focus_child || focus_child == clist->hscrollbar ||
-         focus_child == clist->hscrollbar ||
-         !GTK_CLIST_CHILD_HAS_FOCUS (clist))
+      if (!focus_child || !GTK_CLIST_CHILD_HAS_FOCUS(clist))
        {
          if (dir == GTK_DIR_UP)
            i = COLUMN_FROM_XPIXEL (clist, 0);
          else
-           i = clist->columns - 1;
+           i = last_column;
          focus_child = clist->column[i].button;
          dir = GTK_DIR_TAB_FORWARD;
        }
@@ -5910,16 +6752,14 @@ title_focus (GtkCList * clist,
       break;
     case GTK_DIR_LEFT:
       d = -1;
-      if (!focus_child || focus_child == clist->hscrollbar ||
-         focus_child == clist->hscrollbar)
+      if (!focus_child)
        {
-         i = clist->columns - 1;
+         i = last_column;
          focus_child = clist->column[i].button;
        }
       break;
     case GTK_DIR_RIGHT:
-      if (!focus_child || focus_child == clist->hscrollbar ||
-         focus_child == clist->hscrollbar)
+      if (!focus_child)
        {
          i = 0;
          focus_child = clist->column[i].button;
@@ -5935,7 +6775,7 @@ title_focus (GtkCList * clist,
            if (clist->column[i].button && 
                GTK_WIDGET_VISIBLE (clist->column[i].button) &&
                GTK_IS_CONTAINER (clist->column[i].button) &&
-               !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
+               !GTK_WIDGET_HAS_FOCUS(clist->column[i].button))
              if (gtk_container_focus 
                  (GTK_CONTAINER (clist->column[i].button), dir))
                {
@@ -5982,7 +6822,7 @@ title_focus (GtkCList * clist,
       else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
               clist->clist_window_width)
        {
-         if (j == clist->columns-1)
+         if (j == last_column)
            gtk_clist_moveto (clist, -1, j, 0, 0);
          else
            gtk_clist_moveto (clist, -1, j, 0, 1);
@@ -5991,325 +6831,421 @@ title_focus (GtkCList * clist,
   return return_val;
 }
 
-static gint
-gtk_clist_focus (GtkContainer     * container,
-                GtkDirectionType   direction)
+/* PRIVATE SCROLLING FUNCTIONS
+ *   move_focus_row
+ *   scroll_horizontal
+ *   scroll_vertical
+ *   move_horizontal
+ *   move_vertical
+ *   horizontal_timeout
+ *   vertical_timeout
+ *   remove_grab
+ */
+static void
+move_focus_row (GtkCList      *clist,
+               GtkScrollType  scroll_type,
+               gfloat         position)
 {
-  GtkCList *clist;
-  GtkWidget *focus_child;
-  gint old_row;
+  GtkWidget *widget;
 
-  g_return_val_if_fail (container != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
+  g_return_if_fail (clist != 0);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (!GTK_WIDGET_SENSITIVE (container))
-    return FALSE;
-  
-  clist = GTK_CLIST (container);
-  focus_child = container->focus_child;
-  old_row = clist->focus_row;
+  widget = GTK_WIDGET (clist);
 
-  switch (direction)
+  switch (scroll_type)
     {
-    case GTK_DIR_LEFT:
-    case GTK_DIR_RIGHT:
-      if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
-         (!focus_child || (focus_child && focus_child != clist->vscrollbar && 
-                           focus_child != clist->hscrollbar)))
-       {
-         if (title_focus (clist, direction))
-           return TRUE;
-         gtk_container_set_focus_child (container, NULL);
-         return FALSE;
-        }
-      gtk_widget_grab_focus (GTK_WIDGET (container));
-      return TRUE;
-    case GTK_DIR_DOWN:
-    case GTK_DIR_TAB_FORWARD:
-      if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && 
-         (!focus_child || (focus_child != clist->vscrollbar &&
-                           focus_child != clist->hscrollbar))) 
+    case GTK_SCROLL_STEP_BACKWARD:
+      if (clist->focus_row <= 0)
+       return;
+      gtk_clist_draw_focus (widget);
+      clist->focus_row--;
+      gtk_clist_draw_focus (widget);
+      break;
+    case GTK_SCROLL_STEP_FORWARD:
+      if (clist->focus_row >= clist->rows - 1)
+       return;
+      gtk_clist_draw_focus (widget);
+      clist->focus_row++;
+      gtk_clist_draw_focus (widget);
+      break;
+    case GTK_SCROLL_PAGE_BACKWARD:
+      if (clist->focus_row <= 0)
+       return;
+      gtk_clist_draw_focus (widget);
+      clist->focus_row = MAX (0, clist->focus_row -
+                             (2 * clist->clist_window_height -
+                              clist->row_height - CELL_SPACING) / 
+                             (2 * (clist->row_height + CELL_SPACING)));
+      gtk_clist_draw_focus (widget);
+      break;
+    case GTK_SCROLL_PAGE_FORWARD:
+      if (clist->focus_row >= clist->rows - 1)
+       return;
+      gtk_clist_draw_focus (widget);
+      clist->focus_row = MIN (clist->rows - 1, clist->focus_row + 
+                             (2 * clist->clist_window_height -
+                              clist->row_height - CELL_SPACING) / 
+                             (2 * (clist->row_height + CELL_SPACING)));
+      gtk_clist_draw_focus (widget);
+      break;
+    case GTK_SCROLL_JUMP:
+      if (position >= 0 && position <= 1)
        {
-         gboolean tf = FALSE;
+         gtk_clist_draw_focus (widget);
+         clist->focus_row = position * (clist->rows - 1);
+         gtk_clist_draw_focus (widget);
+       }
+      break;
+    default:
+      break;
+    }
+}
 
-         if (((focus_child && direction == GTK_DIR_DOWN) ||
-              !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
-             && clist->rows)
-           {
-             if (clist->focus_row < 0)
-               {
-                 clist->focus_row = 0;
+static void
+scroll_horizontal (GtkCList      *clist,
+                  GtkScrollType  scroll_type,
+                  gfloat         position)
+{
+  gint column = 0;
+  gint last_column;
 
-                 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
-                      clist->selection_mode == GTK_SELECTION_EXTENDED) &&
-                     !clist->selection)
-                   select_row (clist, clist->focus_row, -1, NULL);
-               }
-             gtk_widget_grab_focus (GTK_WIDGET (container));
-             return TRUE;
-           }
+  g_return_if_fail (clist != 0);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-         if (tf)
-           return TRUE;
-       }
-      
-      GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
+    return;
 
-      if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
-          (focus_child != clist->vscrollbar &&
-           focus_child != clist->hscrollbar)) &&
-         GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
-         GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
-       {
-         gtk_widget_grab_focus (clist->vscrollbar);
-         return TRUE;
-       }
+  for (last_column = clist->columns - 1;
+       last_column >= 0 && !clist->column[last_column].visible; last_column--)
+    ;
 
-      if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || 
-          focus_child != clist->hscrollbar) &&
-         GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
-         GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
-       {
-         gtk_widget_grab_focus (clist->hscrollbar);
-         return TRUE;
-       }
+  switch (scroll_type)
+    {
+    case GTK_SCROLL_STEP_BACKWARD:
+      column = COLUMN_FROM_XPIXEL (clist, 0);
+      if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
+         && column > 0)
+       column--;
       break;
-    case GTK_DIR_UP:
-    case GTK_DIR_TAB_BACKWARD:
-      if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
-         GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
-         GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
+    case GTK_SCROLL_STEP_FORWARD:
+      column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
+      if (column < 0)
+       return;
+      if (COLUMN_LEFT_XPIXEL (clist, column) +
+         clist->column[column].area.width +
+         CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
+         column < last_column)
+       column++;
+      break;
+    case GTK_SCROLL_PAGE_BACKWARD:
+    case GTK_SCROLL_PAGE_FORWARD:
+      return;
+    case GTK_SCROLL_JUMP:
+      if (position >= 0 && position <= 1)
        {
-         gtk_widget_grab_focus (clist->hscrollbar);
-         return TRUE;
+         gint vis_columns = 0;
+         gint i;
+
+         for (i = 0; i <= last_column; i++)
+           if (clist->column[i].visible)
+             vis_columns++;
+
+         column = position * vis_columns;
+
+         for (i = 0; i <= last_column && column > 0; i++)
+           if (clist->column[i].visible)
+             column--;
+
+         column = i;
        }
-       
-      if ((!focus_child || focus_child == clist->hscrollbar) &&
-         GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
-         GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
-         GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
+      else
+       return;
+      break;
+    default:
+      break;
+    }
+
+  if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
+    gtk_clist_moveto (clist, -1, column, 0, 0);
+  else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
+          + clist->column[column].area.width > clist->clist_window_width)
+    {
+      if (column == last_column)
+       gtk_clist_moveto (clist, -1, column, 0, 0);
+      else
+       gtk_clist_moveto (clist, -1, column, 0, 1);
+    }
+}
+
+static void
+scroll_vertical (GtkCList      *clist,
+                GtkScrollType  scroll_type,
+                gfloat         position)
+{
+  gint old_focus_row;
+
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
+    return;
+
+  switch (clist->selection_mode)
+    {
+    case GTK_SELECTION_EXTENDED:
+      if (clist->anchor >= 0)
+       return;
+    case GTK_SELECTION_BROWSE:
+
+      old_focus_row = clist->focus_row;
+      move_focus_row (clist, scroll_type, position);
+
+      if (old_focus_row != clist->focus_row)
        {
-         gtk_widget_grab_focus (clist->vscrollbar);
-         return TRUE;
+         if (clist->selection_mode == GTK_SELECTION_BROWSE)
+           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
+                            old_focus_row, -1, NULL);
+         else if (!GTK_CLIST_ADD_MODE(clist))
+           {
+             gtk_clist_unselect_all (clist);
+             clist->undo_anchor = old_focus_row;
+           }
        }
 
-      if ((!focus_child || focus_child == clist->hscrollbar ||
-          focus_child == clist->vscrollbar) &&
-         GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
+      switch (gtk_clist_row_is_visible (clist, clist->focus_row))
        {
-         if (clist->focus_row < 0)
+       case GTK_VISIBILITY_NONE:
+         if (old_focus_row != clist->focus_row &&
+             !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
+               GTK_CLIST_ADD_MODE(clist)))
+           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                            clist->focus_row, -1, NULL);
+         switch (scroll_type)
            {
-             clist->focus_row = 0;
-             if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
-                  clist->selection_mode == GTK_SELECTION_EXTENDED) &&
-                 !clist->selection)
-               select_row (clist, clist->focus_row, -1, NULL);
+           case GTK_SCROLL_STEP_BACKWARD:
+           case GTK_SCROLL_PAGE_BACKWARD:
+             gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+             break;
+           case GTK_SCROLL_STEP_FORWARD:
+           case GTK_SCROLL_PAGE_FORWARD:
+             gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+             break;
+           case GTK_SCROLL_JUMP:
+             gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
+             break;
+           default:
+             break;
            }
-         gtk_widget_grab_focus (GTK_WIDGET (container));
-         return TRUE;
+         break;
+       case GTK_VISIBILITY_PARTIAL:
+         switch (scroll_type)
+           {
+           case GTK_SCROLL_STEP_BACKWARD:
+           case GTK_SCROLL_PAGE_BACKWARD:
+             gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+             break;
+           case GTK_SCROLL_STEP_FORWARD:
+           case GTK_SCROLL_PAGE_FORWARD:
+             gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+             break;
+           case GTK_SCROLL_JUMP:
+             gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
+             break;
+           default:
+             break;
+           }
+       default:
+         if (old_focus_row != clist->focus_row &&
+             !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
+               GTK_CLIST_ADD_MODE(clist)))
+           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
+                            clist->focus_row, -1, NULL);
+         break;
        }
+      break;
+    default:
+      move_focus_row (clist, scroll_type, position);
+
+      if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
+         clist->clist_window_height)
+       gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
+      else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
+       gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
+      break;
+    }
+}
+
+static void
+move_horizontal (GtkCList *clist,
+                gint      diff)
+{
+  gfloat value;
 
-      GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
+  if (!clist->hadjustment)
+    return;
 
-      if (title_focus (clist, direction))
-       return TRUE;
+  value = CLAMP (clist->hadjustment->value + diff, 0.0,
+                clist->hadjustment->upper - clist->hadjustment->page_size);
+  gtk_adjustment_set_value(clist->hadjustment, value);
+}
 
-      break;
+static void
+move_vertical (GtkCList *clist,
+              gint      row,
+              gfloat    align)
+{
+  gfloat value;
 
-    default:
-      break;
-    }
+  if (!clist->vadjustment)
+    return;
 
-  gtk_container_set_focus_child (container, NULL);
-  return FALSE;
+  value = (ROW_TOP_YPIXEL (clist, row) - clist->voffset -
+          align * (clist->clist_window_height - clist->row_height) +
+          (2 * align - 1) * CELL_SPACING);
+
+  if (value + clist->vadjustment->page_size > clist->vadjustment->upper)
+    value = clist->vadjustment->upper - clist->vadjustment->page_size;
+
+  gtk_adjustment_set_value(clist->vadjustment, value);
 }
 
-void
-gtk_clist_unselect_all (GtkCList * clist)
+static gint
+horizontal_timeout (GtkCList *clist)
 {
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  GdkEventMotion event = { 0 };
 
-  GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
+  GDK_THREADS_ENTER ();
+
+  clist->htimer = 0;
+
+  event.type = GDK_MOTION_NOTIFY;
+  event.send_event = TRUE;
+
+  gtk_clist_motion (GTK_WIDGET (clist), &event);
+
+  GDK_THREADS_LEAVE ();
+  
+  return FALSE;
 }
 
-static void
-real_unselect_all (GtkCList * clist)
+static gint
+vertical_timeout (GtkCList *clist)
 {
-  GList *list;
-  gint i;
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  GdkEventMotion event = { 0 };
 
-  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
-    return;
+  GDK_THREADS_ENTER ();
 
-  switch (clist->selection_mode)
-    {
-    case GTK_SELECTION_BROWSE:
-      if (clist->focus_row >= 0)
-       {
-         select_row (clist, clist->focus_row, -1, NULL);
-         return;
-       }
-      break;
+  clist->vtimer = 0;
 
-    case GTK_SELECTION_EXTENDED:
-      g_list_free (clist->undo_selection);
-      g_list_free (clist->undo_unselection);
-      clist->undo_selection = NULL;
-      clist->undo_unselection = NULL;
+  event.type = GDK_MOTION_NOTIFY;
+  event.send_event = TRUE;
 
-      clist->anchor = -1;
-      clist->drag_pos = -1;
-      clist->undo_anchor = clist->focus_row;
-      break;
+  gtk_clist_motion (GTK_WIDGET (clist), &event);
 
-    default:
-      break;
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+remove_grab (GtkCList *clist)
+{
+  if (GTK_WIDGET_HAS_GRAB (clist))
+    {
+      gtk_grab_remove (GTK_WIDGET (clist));
+      if (gdk_pointer_is_grabbed ())
+       gdk_pointer_ungrab (GDK_CURRENT_TIME);
     }
 
-  list = clist->selection;
+  if (clist->htimer)
+    {
+      gtk_timeout_remove (clist->htimer);
+      clist->htimer = 0;
+    }
 
-  while (list)
+  if (clist->vtimer)
     {
-      i = GPOINTER_TO_INT (list->data);
-      list = list->next;
-      unselect_row (clist, i, -1, NULL);
+      gtk_timeout_remove (clist->vtimer);
+      clist->vtimer = 0;
     }
 }
 
+/* PUBLIC SORTING FUNCTIONS
+ * gtk_clist_sort
+ * gtk_clist_set_compare_func
+ * gtk_clist_set_auto_sort
+ * gtk_clist_set_sort_type
+ * gtk_clist_set_sort_column
+ */
 void
-gtk_clist_select_all (GtkCList * clist)
+gtk_clist_sort (GtkCList *clist)
 {
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  GTK_CLIST_CLASS_FW (clist)->select_all (clist);
+  GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
 }
 
-static void
-real_select_all (GtkCList * clist)
+void
+gtk_clist_set_compare_func (GtkCList            *clist,
+                           GtkCListCompareFunc  cmp_func)
 {
-  GList *list;
-  gint i;
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
-    return;
-
-  switch (clist->selection_mode)
-    {
-    case GTK_SELECTION_SINGLE:
-    case GTK_SELECTION_BROWSE:
-      return;
-
-    case GTK_SELECTION_EXTENDED:
-      g_list_free (clist->undo_selection);
-      g_list_free (clist->undo_unselection);
-      clist->undo_selection = NULL;
-      clist->undo_unselection = NULL;
-         
-      if (clist->rows &&
-         ((GtkCListRow *) (clist->row_list->data))->state !=
-         GTK_STATE_SELECTED)
-       fake_toggle_row (clist, 0);
-
-      clist->anchor_state =  GTK_STATE_SELECTED;
-      clist->anchor = 0;
-      clist->drag_pos = 0;
-      clist->undo_anchor = clist->focus_row;
-      update_extended_selection (clist, clist->rows);
-      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
-      return;
-
-    case GTK_SELECTION_MULTIPLE:
-      for (i = 0, list = clist->row_list; list; i++, list = list->next)
-       {
-         if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
-           gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
-                            i, -1, NULL);
-       }
-      return;
-    }
+  clist->compare = (cmp_func) ? cmp_func : default_compare;
 }
 
-static void
-fake_unselect_all (GtkCList * clist,
-                  gint       row)
+void       
+gtk_clist_set_auto_sort (GtkCList *clist,
+                        gboolean  auto_sort)
 {
-  GList *list;
-  GList *work;
-  gint i;
-
-  if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
-    {
-      if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
-         GTK_CLIST_ROW (work)->selectable)
-       {
-         GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
-         
-         if (!GTK_CLIST_FROZEN (clist) &&
-             gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
-           GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
-                                                 GTK_CLIST_ROW (work));
-       }  
-    }
-
-  clist->undo_selection = clist->selection;
-  clist->selection = NULL;
-  clist->selection_end = NULL;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
   
-  for (list = clist->undo_selection; list; list = list->next)
+  if (GTK_CLIST_AUTO_SORT(clist) && !auto_sort)
+    GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
+  else if (!GTK_CLIST_AUTO_SORT(clist) && auto_sort)
     {
-      if ((i = GPOINTER_TO_INT (list->data)) == row ||
-         !(work = g_list_nth (clist->row_list, i)))
-       continue;
-
-      GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
-      if (!GTK_CLIST_FROZEN (clist) &&
-         gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
-       GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
-                                             GTK_CLIST_ROW (work));
+      GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
+      gtk_clist_sort (clist);
     }
 }
 
-static void
-fake_toggle_row (GtkCList *clist,
-                gint      row)
+void       
+gtk_clist_set_sort_type (GtkCList    *clist,
+                        GtkSortType  sort_type)
 {
-  GList *work;
-
-  if (!(work = g_list_nth (clist->row_list, row))||
-      !GTK_CLIST_ROW (work)->selectable)
-    return;
-  
-  if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
-    clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
-  else
-    clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
   
-  if (!GTK_CLIST_FROZEN (clist) &&
-      gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
-    GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
-                                         GTK_CLIST_ROW (work));
+  clist->sort_type = sort_type;
 }
 
-static GList *
-selection_find (GtkCList *clist,
-               gint      row_number,
-               GList    *row_list_element)
+void
+gtk_clist_set_sort_column (GtkCList *clist,
+                          gint      column)
 {
-  return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+
+  if (column < 0 || column >= clist->columns)
+    return;
+
+  clist->sort_column = column;
 }
 
+/* PRIVATE SORTING FUNCTIONS
+ *   default_compare
+ *   real_sort_list
+ *   gtk_clist_merge
+ *   gtk_clist_mergesort
+ */
 static gint
-default_compare (GtkCList     *clist,
-                gconstpointer ptr1,
-                gconstpointer ptr2)
+default_compare (GtkCList      *clist,
+                gconstpointer  ptr1,
+                gconstpointer  ptr2)
 {
   char *text1 = NULL;
   char *text2 = NULL;
@@ -6350,53 +7286,50 @@ default_compare (GtkCList     *clist,
   return strcmp (text1, text2);
 }
 
-void
-gtk_clist_set_compare_func (GtkCList            *clist,
-                           GtkCListCompareFunc  cmp_func)
+static void
+real_sort_list (GtkCList *clist)
 {
+  GList *list;
+  GList *work;
+  gint i;
+
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  clist->compare = (cmp_func) ? cmp_func : default_compare;
-}
+  if (clist->rows <= 1)
+    return;
 
-void       
-gtk_clist_set_auto_sort (GtkCList *clist,
-                        gboolean  auto_sort)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-  
-  if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
-    GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
-  else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
+  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
+    return;
+
+  gtk_clist_freeze (clist);
+
+  if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
     {
-      GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
-      gtk_clist_sort (clist);
+      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+      g_list_free (clist->undo_selection);
+      g_list_free (clist->undo_unselection);
+      clist->undo_selection = NULL;
+      clist->undo_unselection = NULL;
     }
-}
-
-void       
-gtk_clist_set_sort_type (GtkCList   *clist,
-                        GtkSortType sort_type)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
-  
-  clist->sort_type = sort_type;
-}
+   
+  clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
 
-void
-gtk_clist_set_sort_column (GtkCList *clist,
-                          gint      column)
-{
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  work = clist->selection;
 
-  if (column < 0 || column >= clist->columns)
-    return;
+  for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
+    {
+      if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
+       {
+         work->data = GINT_TO_POINTER (i);
+         work = work->next;
+       }
+      
+      if (i == clist->rows - 1)
+       clist->row_list_end = list;
+    }
 
-  clist->sort_column = column;
+  gtk_clist_thaw (clist);
 }
 
 static GList *
@@ -6483,63 +7416,479 @@ gtk_clist_mergesort (GtkCList *clist,
     }
 }
 
-void
-gtk_clist_sort (GtkCList *clist)
+/************************/
+
+static void
+drag_source_info_destroy (gpointer data)
 {
-  g_return_if_fail (clist != NULL);
-  g_return_if_fail (GTK_IS_CLIST (clist));
+  GtkCListCellInfo *info = data;
 
-  GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
+  g_free (info);
 }
 
 static void
-real_sort_list (GtkCList *clist)
+drag_dest_info_destroy (gpointer data)
 {
-  GList *list;
-  GList *work;
-  gint i;
-  gboolean thaw = FALSE;
+  GtkCListDestInfo *info = data;
+
+  g_free (info);
+}
+
+static void
+drag_dest_cell (GtkCList         *clist,
+               gint              x,
+               gint              y,
+               GtkCListDestInfo *dest_info)
+{
+  GtkWidget *widget;
+
+  widget = GTK_WIDGET (clist);
+
+  dest_info->insert_pos = GTK_CLIST_DRAG_NONE;
+
+  y -= (GTK_CONTAINER (clist)->border_width +
+       widget->style->klass->ythickness +
+       clist->column_title_area.height);
+
+  dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
+  if (dest_info->cell.row >= clist->rows)
+    {
+      dest_info->cell.row = clist->rows - 1;
+      y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
+    }
+  if (dest_info->cell.row < -1)
+    dest_info->cell.row = -1;
+
+  x -= GTK_CONTAINER (widget)->border_width + widget->style->klass->xthickness;
+  dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
+
+  if (dest_info->cell.row >= 0)
+    {
+      gint y_delta;
+      gint h = 0;
+
+      y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
+      
+      if (GTK_CLIST_DRAW_DRAG_RECT(clist))
+       {
+         dest_info->insert_pos = GTK_CLIST_DRAG_INTO;
+         h = clist->row_height / 4;
+       }
+      else if (GTK_CLIST_DRAW_DRAG_LINE(clist))
+       {
+         dest_info->insert_pos = GTK_CLIST_DRAG_BEFORE;
+         h = clist->row_height / 2;
+       }
+
+      if (GTK_CLIST_DRAW_DRAG_LINE(clist))
+       {
+         if (y_delta < h)
+           dest_info->insert_pos = GTK_CLIST_DRAG_BEFORE;
+         else if (clist->row_height - y_delta < h)
+           dest_info->insert_pos = GTK_CLIST_DRAG_AFTER;
+       }
+    }
+}
+
+static void
+gtk_clist_drag_begin (GtkWidget             *widget,
+                     GdkDragContext *context)
+{
+  GtkCList *clist;
+  GtkCListCellInfo *info;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (context != NULL);
+
+  clist = GTK_CLIST (widget);
+
+  clist->drag_button = 0;
+  remove_grab (clist);
+
+  switch (clist->selection_mode)
+    {
+    case GTK_SELECTION_EXTENDED:
+      update_extended_selection (clist, clist->focus_row);
+      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+      break;
+    case GTK_SELECTION_SINGLE:
+    case GTK_SELECTION_MULTIPLE:
+      clist->anchor = -1;
+    case GTK_SELECTION_BROWSE:
+      break;
+    }
+
+  info = g_dataset_get_data (context, "gtk-clist-drag-source");
+
+  if (!info)
+    {
+      info = g_new (GtkCListCellInfo, 1);
+
+      if (clist->click_cell.row < 0)
+       clist->click_cell.row = 0;
+      else if (clist->click_cell.row >= clist->rows)
+       clist->click_cell.row = clist->rows - 1;
+      info->row = clist->click_cell.row;
+      info->column = clist->click_cell.column;
+
+      g_dataset_set_data_full (context, "gtk-clist-drag-source", info,
+                              drag_source_info_destroy);
+    }
+
+  if (GTK_CLIST_USE_DRAG_ICONS (clist))
+    gtk_drag_set_icon_default (context);
+}
+
+static void
+gtk_clist_drag_end (GtkWidget     *widget,
+                   GdkDragContext *context)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (context != NULL);
+
+  clist = GTK_CLIST (widget);
+
+  clist->click_cell.row = -1;
+  clist->click_cell.column = -1;
+}
+
+static void
+gtk_clist_drag_leave (GtkWidget      *widget,
+                     GdkDragContext *context,
+                     guint           time)
+{
+  GtkCList *clist;
+  GtkCListDestInfo *dest_info;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (context != NULL);
+
+  clist = GTK_CLIST (widget);
+
+  dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
+  
+  if (dest_info)
+    {
+      if (dest_info->cell.row >= 0 &&
+         GTK_CLIST_REORDERABLE(clist) &&
+         gtk_drag_get_source_widget (context) == widget)
+       {
+         GList *list;
+         GdkAtom atom = gdk_atom_intern ("gtk-clist-drag-reorder", FALSE);
+
+         list = context->targets;
+         while (list)
+           {
+             if (atom == GPOINTER_TO_INT (list->data))
+               {
+                 GTK_CLIST_CLASS_FW (clist)->draw_drag_highlight
+                   (clist,
+                    g_list_nth (clist->row_list, dest_info->cell.row)->data,
+                    dest_info->cell.row, dest_info->insert_pos);
+                 break;
+               }
+             list = list->next;
+           }
+       }
+      g_dataset_remove_data (context, "gtk-clist-drag-dest");
+    }
+}
+
+static gint
+gtk_clist_drag_motion (GtkWidget      *widget,
+                      GdkDragContext *context,
+                      gint            x,
+                      gint            y,
+                      guint           time)
+{
+  GtkCList *clist;
+  GtkCListDestInfo new_info;
+  GtkCListDestInfo *dest_info;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
+
+  clist = GTK_CLIST (widget);
+
+  dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
+
+  if (!dest_info)
+    {
+      dest_info = g_new (GtkCListDestInfo, 1);
+
+      dest_info->insert_pos  = GTK_CLIST_DRAG_NONE;
+      dest_info->cell.row    = -1;
+      dest_info->cell.column = -1;
+
+      g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
+                              drag_dest_info_destroy);
+    }
+
+  drag_dest_cell (clist, x, y, &new_info);
+
+  if (GTK_CLIST_REORDERABLE (clist))
+    {
+      GList *list;
+      GdkAtom atom = gdk_atom_intern ("gtk-clist-drag-reorder", FALSE);
+
+      list = context->targets;
+      while (list)
+       {
+         if (atom == GPOINTER_TO_INT (list->data))
+           break;
+         list = list->next;
+       }
+
+      if (list)
+       {
+         if (gtk_drag_get_source_widget (context) != widget ||
+             new_info.insert_pos == GTK_CLIST_DRAG_NONE ||
+             new_info.cell.row == clist->click_cell.row ||
+             (new_info.cell.row == clist->click_cell.row - 1 &&
+              new_info.insert_pos == GTK_CLIST_DRAG_AFTER) ||
+             (new_info.cell.row == clist->click_cell.row + 1 &&
+              new_info.insert_pos == GTK_CLIST_DRAG_BEFORE))
+           {
+             if (dest_info->cell.row < 0)
+               {
+                 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
+                 return FALSE;
+               }
+             return TRUE;
+           }
+               
+         if (new_info.cell.row != dest_info->cell.row ||
+             (new_info.cell.row == dest_info->cell.row &&
+              dest_info->insert_pos != new_info.insert_pos))
+           {
+             if (dest_info->cell.row >= 0)
+               GTK_CLIST_CLASS_FW (clist)->draw_drag_highlight
+                 (clist, g_list_nth (clist->row_list,
+                                     dest_info->cell.row)->data,
+                  dest_info->cell.row, dest_info->insert_pos);
+
+             dest_info->insert_pos  = new_info.insert_pos;
+             dest_info->cell.row    = new_info.cell.row;
+             dest_info->cell.column = new_info.cell.column;
+             
+             GTK_CLIST_CLASS_FW (clist)->draw_drag_highlight
+               (clist, g_list_nth (clist->row_list,
+                                   dest_info->cell.row)->data,
+                dest_info->cell.row, dest_info->insert_pos);
+
+             gdk_drag_status (context, context->suggested_action, time);
+           }
+         return TRUE;
+       }
+    }
+
+  dest_info->insert_pos  = new_info.insert_pos;
+  dest_info->cell.row    = new_info.cell.row;
+  dest_info->cell.column = new_info.cell.column;
+  return TRUE;
+}
+
+static gboolean
+gtk_clist_drag_drop (GtkWidget      *widget,
+                    GdkDragContext *context,
+                    gint            x,
+                    gint            y,
+                    guint           time)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
+  g_return_val_if_fail (context != NULL, FALSE);
+
+  if (GTK_CLIST_REORDERABLE (widget) &&
+      gtk_drag_get_source_widget (context) == widget)
+    {
+      GList *list;
+      GdkAtom atom = gdk_atom_intern ("gtk-clist-drag-reorder", FALSE);
+
+      list = context->targets;
+      while (list)
+       {
+         if (atom == GPOINTER_TO_INT (list->data))
+           return TRUE;
+         list = list->next;
+       }
+    }
+  return FALSE;
+}
+
+static void
+gtk_clist_drag_data_received (GtkWidget        *widget,
+                             GdkDragContext   *context,
+                             gint              x,
+                             gint              y,
+                             GtkSelectionData *selection_data,
+                             guint             info,
+                             guint             time)
+{
+  GtkCList *clist;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (context != NULL);
+  g_return_if_fail (selection_data != NULL);
+
+  clist = GTK_CLIST (widget);
+
+  if (GTK_CLIST_REORDERABLE (clist) &&
+      gtk_drag_get_source_widget (context) == widget &&
+      selection_data->target ==
+      gdk_atom_intern ("gtk-clist-drag-reorder", FALSE) &&
+      selection_data->format == GTK_TYPE_POINTER &&
+      selection_data->length == sizeof (GtkCListCellInfo))
+    {
+      GtkCListCellInfo *source_info;
+
+      source_info = (GtkCListCellInfo *)(selection_data->data);
+      if (source_info)
+       {
+         GtkCListDestInfo dest_info;
+
+         drag_dest_cell (clist, x, y, &dest_info);
+
+         if (dest_info.insert_pos == GTK_CLIST_DRAG_AFTER)
+           dest_info.cell.row++;
+         if (source_info->row < dest_info.cell.row)
+           dest_info.cell.row--;
+         if (dest_info.cell.row != source_info->row)
+           gtk_clist_row_move (clist, source_info->row, dest_info.cell.row);
+
+         g_dataset_remove_data (context, "gtk-clist-drag-dest");
+       }
+    }
+}
+
+static void  
+gtk_clist_drag_data_get (GtkWidget        *widget,
+                        GdkDragContext   *context,
+                        GtkSelectionData *selection_data,
+                        guint             info,
+                        guint             time)
+{
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_CLIST (widget));
+  g_return_if_fail (context != NULL);
+  g_return_if_fail (selection_data != NULL);
+
+  if (selection_data->target ==
+      gdk_atom_intern ("gtk-clist-drag-reorder", FALSE))
+    {
+      GtkCListCellInfo *info;
+
+      info = g_dataset_get_data (context, "gtk-clist-drag-source");
+
+      if (info)
+       {
+         GtkCListCellInfo ret_info;
+
+         ret_info.row = info->row;
+         ret_info.column = info->column;
+
+         gtk_selection_data_set (selection_data, selection_data->target,
+                                 GTK_TYPE_POINTER, (guchar *) &ret_info,
+                                 sizeof (GtkCListCellInfo));
+       }
+      else
+       gtk_selection_data_set (selection_data, selection_data->target,
+                               GTK_TYPE_POINTER, NULL, 0);
+    }
+}
+
+static void
+draw_drag_highlight (GtkCList        *clist,
+                    GtkCListRow     *dest_row,
+                    gint             dest_row_number,
+                    GtkCListDragPos  drag_pos)
+{
+  gint y;
+
+  y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1;
+
+  switch (drag_pos)
+    {
+    case GTK_CLIST_DRAG_NONE:
+      break;
+    case GTK_CLIST_DRAG_AFTER:
+      y += clist->row_height + 1;
+    case GTK_CLIST_DRAG_BEFORE:
+      gdk_draw_line (clist->clist_window, clist->xor_gc,
+                    0, y, clist->clist_window_width, y);
+      break;
+    case GTK_CLIST_DRAG_INTO:
+      gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
+                         clist->clist_window_width - 1, clist->row_height);
+      break;
+    }
+}
+
+void
+gtk_clist_set_reorderable (GtkCList *clist, 
+                          gboolean  reorderable)
+{
+  GtkWidget *widget;
 
   g_return_if_fail (clist != NULL);
   g_return_if_fail (GTK_IS_CLIST (clist));
 
-  if (clist->rows <= 1)
+  if ((GTK_CLIST_REORDERABLE(clist) != 0) == reorderable)
     return;
 
-  if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
-    return;
+  widget = GTK_WIDGET (clist);
 
-  if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
+  if (reorderable)
     {
-      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
-      g_list_free (clist->undo_selection);
-      g_list_free (clist->undo_unselection);
-      clist->undo_selection = NULL;
-      clist->undo_unselection = NULL;
+      GTK_CLIST_SET_FLAG (clist, CLIST_REORDERABLE);
+      gtk_drag_dest_set (widget,
+                        GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+                        &clist_target_table, 1, GDK_ACTION_MOVE);
     }
-   
-  if (!GTK_CLIST_FROZEN (clist))
+  else
     {
-      gtk_clist_freeze (clist);
-      thaw = TRUE;
+      GTK_CLIST_UNSET_FLAG (clist, CLIST_REORDERABLE);
+      gtk_drag_dest_unset (GTK_WIDGET (clist));
     }
+}
 
-  clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
+void
+gtk_clist_set_use_drag_icons (GtkCList *clist,
+                             gboolean  use_icons)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
 
-  work = clist->selection;
+  if (use_icons != 0)
+    GTK_CLIST_SET_FLAG (clist, CLIST_USE_DRAG_ICONS);
+  else
+    GTK_CLIST_UNSET_FLAG (clist, CLIST_USE_DRAG_ICONS);
+}
 
-  for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
+void
+gtk_clist_set_button_actions (GtkCList *clist,
+                             guint     button,
+                             guint8    button_actions)
+{
+  g_return_if_fail (clist != NULL);
+  g_return_if_fail (GTK_IS_CLIST (clist));
+  
+  if (button < MAX_BUTTON)
     {
-      if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
+      if (gdk_pointer_is_grabbed () || GTK_WIDGET_HAS_GRAB (clist))
        {
-         work->data = GINT_TO_POINTER (i);
-         work = work->next;
+         remove_grab (clist);
+         clist->drag_button = 0;
        }
-      
-      if (i == clist->rows - 1)
-       clist->row_list_end = list;
-    }
 
-  if (thaw)
-    gtk_clist_thaw (clist);
+      GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
+
+      clist->button_actions[button] = button_actions;
+    }
 }