]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeviewcolumn.c
change GTK_MOVEMENT_PARAGRAPHS to go to start/end of paragraph before it
[~andy/gtk] / gtk / gtktreeviewcolumn.c
1 /* gtktreeviewcolumn.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gtktreeviewcolumn.h"
21 #include "gtktreeview.h"
22 #include "gtktreeprivate.h"
23 #include "gtksignal.h"
24 #include "gtkbutton.h"
25 #include "gtkalignment.h"
26 #include "gtklabel.h"
27 #include "gtkhbox.h"
28 #include "gtkmarshalers.h"
29 #include "gtkarrow.h"
30 #include "gtkintl.h"
31 #include <string.h>
32
33 enum
34 {
35   PROP_0,
36   PROP_VISIBLE,
37   PROP_RESIZABLE,
38   PROP_WIDTH,
39   PROP_SIZING,
40   PROP_FIXED_WIDTH,
41   PROP_MIN_WIDTH,
42   PROP_MAX_WIDTH,
43   PROP_TITLE,
44   PROP_CLICKABLE,
45   PROP_WIDGET,
46   PROP_ALIGNMENT,
47   PROP_REORDERABLE,
48   PROP_SORT_INDICATOR,
49   PROP_SORT_ORDER
50 };
51
52 enum
53 {
54   CLICKED,
55   LAST_SIGNAL
56 };
57
58 typedef struct _GtkTreeViewColumnCellInfo GtkTreeViewColumnCellInfo;
59 struct _GtkTreeViewColumnCellInfo
60 {
61   GtkCellRenderer *cell;
62   GSList *attributes;
63   GtkTreeCellDataFunc func;
64   gpointer func_data;
65   GtkDestroyNotify destroy;
66   gint requested_width;
67   guint expand : 1;
68   guint pack : 1;
69   guint has_focus : 1;
70 };
71
72 /* Type methods */
73 static void gtk_tree_view_column_init                          (GtkTreeViewColumn       *tree_column);
74 static void gtk_tree_view_column_class_init                    (GtkTreeViewColumnClass  *klass);
75
76 /* GObject methods */
77 static void gtk_tree_view_column_set_property                  (GObject                 *object,
78                                                                 guint                    prop_id,
79                                                                 const GValue            *value,
80                                                                 GParamSpec              *pspec);
81 static void gtk_tree_view_column_get_property                  (GObject                 *object,
82                                                                 guint                    prop_id,
83                                                                 GValue                  *value,
84                                                                 GParamSpec              *pspec);
85 static void gtk_tree_view_column_finalize                      (GObject                 *object);
86
87 /* Button handling code */ 
88 static void gtk_tree_view_column_create_button                 (GtkTreeViewColumn       *tree_column);
89 static void gtk_tree_view_column_update_button                 (GtkTreeViewColumn       *tree_column);
90
91 /* Button signal handlers */
92 static gint gtk_tree_view_column_button_event                  (GtkWidget               *widget,
93                                                                 GdkEvent                *event,
94                                                                 gpointer                 data);
95 static void gtk_tree_view_column_button_realize                (GtkWidget               *widget,
96                                                                 gpointer                 data);
97 static void gtk_tree_view_column_button_clicked                (GtkWidget               *widget,
98                                                                 gpointer                 data);
99
100 /* Property handlers */
101 static void gtk_tree_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
102                                                                 GtkTreeViewColumn       *tree_column);
103
104 /* Internal functions */
105 static void gtk_tree_view_column_sort                          (GtkTreeViewColumn       *tree_column,
106                                                                 gpointer                 data);
107 static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn       *tree_column);
108 static void gtk_tree_view_column_set_attributesv               (GtkTreeViewColumn       *tree_column,
109                                                                 GtkCellRenderer         *cell_renderer,
110                                                                 va_list                  args);
111 static GtkTreeViewColumnCellInfo *gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
112                                                                       GtkCellRenderer   *cell_renderer);
113
114
115
116 static GtkObjectClass *parent_class = NULL;
117 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
118
119
120 GtkType
121 gtk_tree_view_column_get_type (void)
122 {
123   static GtkType tree_column_type = 0;
124
125   if (!tree_column_type)
126     {
127       static const GTypeInfo tree_column_info =
128       {
129         sizeof (GtkTreeViewColumnClass),
130         NULL,           /* base_init */
131         NULL,           /* base_finalize */
132         (GClassInitFunc) gtk_tree_view_column_class_init,
133         NULL,           /* class_finalize */
134         NULL,           /* class_data */
135         sizeof (GtkTreeViewColumn),
136         0,
137         (GInstanceInitFunc) gtk_tree_view_column_init,
138       };
139
140       tree_column_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn", &tree_column_info, 0);
141     }
142
143   return tree_column_type;
144 }
145
146 static void
147 gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
148 {
149   GObjectClass *object_class;
150
151   object_class = (GObjectClass*) class;
152
153   parent_class = g_type_class_peek_parent (class);
154
155   class->clicked = NULL;
156
157   object_class->finalize = gtk_tree_view_column_finalize;
158   object_class->set_property = gtk_tree_view_column_set_property;
159   object_class->get_property = gtk_tree_view_column_get_property;
160   
161   tree_column_signals[CLICKED] =
162     g_signal_new ("clicked",
163                   GTK_CLASS_TYPE (object_class),
164                   G_SIGNAL_RUN_LAST,
165                   G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
166                   NULL, NULL,
167                   _gtk_marshal_VOID__VOID,
168                   GTK_TYPE_NONE, 0);
169
170   g_object_class_install_property (object_class,
171                                    PROP_VISIBLE,
172                                    g_param_spec_boolean ("visible",
173                                                         _("Visible"),
174                                                         _("Whether to display the column"),
175                                                          TRUE,
176                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
177   
178   g_object_class_install_property (object_class,
179                                    PROP_RESIZABLE,
180                                    g_param_spec_boolean ("resizable",
181                                                          _("Resizable"),
182                                                          _("Column is user-resizable"),
183                                                          FALSE,
184                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
185   
186   g_object_class_install_property (object_class,
187                                    PROP_WIDTH,
188                                    g_param_spec_int ("width",
189                                                      _("Width"),
190                                                      _("Current width of the column"),
191                                                      0,
192                                                      G_MAXINT,
193                                                      0,
194                                                      G_PARAM_READABLE));
195   g_object_class_install_property (object_class,
196                                    PROP_SIZING,
197                                    g_param_spec_enum ("sizing",
198                                                       _("Sizing"),
199                                                       _("Resize mode of the column"),
200                                                       GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
201                                                       GTK_TREE_VIEW_COLUMN_AUTOSIZE,
202                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
203   
204   g_object_class_install_property (object_class,
205                                    PROP_FIXED_WIDTH,
206                                    g_param_spec_int ("fixed_width",
207                                                      _("Fixed Width"),
208                                                      _("Current fixed width of the column"),
209                                                      1,
210                                                      G_MAXINT,
211                                                      1, /* not useful */
212                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
213
214   g_object_class_install_property (object_class,
215                                    PROP_MIN_WIDTH,
216                                    g_param_spec_int ("min_width",
217                                                      _("Minimum Width"),
218                                                      _("Minimum allowed width of the column"),
219                                                      -1,
220                                                      G_MAXINT,
221                                                      -1,
222                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
223
224   g_object_class_install_property (object_class,
225                                    PROP_MAX_WIDTH,
226                                    g_param_spec_int ("max_width",
227                                                      _("Maximum Width"),
228                                                      _("Maximum allowed width of the column"),
229                                                      -1,
230                                                      G_MAXINT,
231                                                      -1,
232                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
233
234   g_object_class_install_property (object_class,
235                                    PROP_TITLE,
236                                    g_param_spec_string ("title",
237                                                         _("Title"),
238                                                         _("Title to appear in column header"),
239                                                         "",
240                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
241   
242   g_object_class_install_property (object_class,
243                                    PROP_CLICKABLE,
244                                    g_param_spec_boolean ("clickable",
245                                                         _("Clickable"),
246                                                         _("Whether the header can be clicked"),
247                                                          TRUE,
248                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
249   
250
251   g_object_class_install_property (object_class,
252                                    PROP_WIDGET,
253                                    g_param_spec_object ("widget",
254                                                         _("Widget"),
255                                                         _("Widget to put in column header button instead of column title"),
256                                                         GTK_TYPE_WIDGET,
257                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
258
259   g_object_class_install_property (object_class,
260                                    PROP_ALIGNMENT,
261                                    g_param_spec_float ("alignment",
262                                                        _("Alignment"),
263                                                        _("X Alignment of the column header text or widget"),
264                                                        0.0,
265                                                        1.0,
266                                                        0.5,
267                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
268
269   g_object_class_install_property (object_class,
270                                    PROP_REORDERABLE,
271                                    g_param_spec_boolean ("reorderable",
272                                                          _("Reorderable"),
273                                                          _("Whether the column can be reordered around the headers"),
274                                                          FALSE,
275                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
276
277   g_object_class_install_property (object_class,
278                                    PROP_SORT_INDICATOR,
279                                    g_param_spec_boolean ("sort_indicator",
280                                                         _("Sort indicator"),
281                                                         _("Whether to show a sort indicator"),
282                                                          FALSE,
283                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
284
285   g_object_class_install_property (object_class,
286                                    PROP_SORT_ORDER,
287                                    g_param_spec_enum ("sort_order",
288                                                       _("Sort order"),
289                                                       _("Sort direction the sort indicator should indicate"),
290                                                       GTK_TYPE_SORT_TYPE,
291                                                       GTK_SORT_ASCENDING,
292                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
293   
294 }
295
296 static void
297 gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
298 {
299   tree_column->button = NULL;
300   tree_column->xalign = 0.0;
301   tree_column->width = 0;
302   tree_column->requested_width = -1;
303   tree_column->min_width = -1;
304   tree_column->max_width = -1;
305   tree_column->resized_width = 0;
306   tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
307   tree_column->visible = TRUE;
308   tree_column->resizable = FALSE;
309   tree_column->clickable = FALSE;
310   tree_column->dirty = TRUE;
311   tree_column->sort_order = GTK_SORT_ASCENDING;
312   tree_column->show_sort_indicator = FALSE;
313   tree_column->property_changed_signal = 0;
314   tree_column->sort_clicked_signal = 0;
315   tree_column->sort_column_changed_signal = 0;
316   tree_column->sort_column_id = -1;
317   tree_column->reorderable = FALSE;
318   tree_column->maybe_reordered = FALSE;
319   tree_column->use_resized_width = FALSE;
320 }
321
322 static void
323 gtk_tree_view_column_finalize (GObject *object)
324 {
325   GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
326   GList *list;
327
328   for (list = tree_column->cell_list; list; list = list->next)
329     {
330       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
331       if (info->func_data && info->destroy)
332         (info->destroy) (info->func_data);
333       gtk_tree_view_column_clear_attributes (tree_column, info->cell);
334       g_object_unref (G_OBJECT (info->cell));
335       g_free (info);
336     }
337
338   g_free (tree_column->title);
339
340   G_OBJECT_CLASS (parent_class)->finalize (object);
341 }
342
343 static void
344 gtk_tree_view_column_set_property (GObject         *object,
345                                    guint            prop_id,
346                                    const GValue    *value,
347                                    GParamSpec      *pspec)
348 {
349   GtkTreeViewColumn *tree_column;
350
351   tree_column = GTK_TREE_VIEW_COLUMN (object);
352
353   switch (prop_id)
354     {
355     case PROP_VISIBLE:
356       gtk_tree_view_column_set_visible (tree_column,
357                                         g_value_get_boolean (value));
358       break;
359
360     case PROP_RESIZABLE:
361       gtk_tree_view_column_set_resizable (tree_column,
362                                           g_value_get_boolean (value));
363       break;
364
365     case PROP_SIZING:
366       gtk_tree_view_column_set_sizing (tree_column,
367                                        g_value_get_enum (value));
368       break;
369
370     case PROP_FIXED_WIDTH:
371       gtk_tree_view_column_set_fixed_width (tree_column,
372                                             g_value_get_int (value));
373       break;
374
375     case PROP_MIN_WIDTH:
376       gtk_tree_view_column_set_min_width (tree_column,
377                                           g_value_get_int (value));
378       break;
379
380     case PROP_MAX_WIDTH:
381       gtk_tree_view_column_set_max_width (tree_column,
382                                           g_value_get_int (value));
383       break;
384
385     case PROP_TITLE:
386       gtk_tree_view_column_set_title (tree_column,
387                                       g_value_get_string (value));
388       break;
389
390     case PROP_CLICKABLE:
391       gtk_tree_view_column_set_clickable (tree_column,
392                                           g_value_get_boolean (value));
393       break;
394
395     case PROP_WIDGET:
396       gtk_tree_view_column_set_widget (tree_column,
397                                        (GtkWidget*) g_value_get_object (value));
398       break;
399
400     case PROP_ALIGNMENT:
401       gtk_tree_view_column_set_alignment (tree_column,
402                                           g_value_get_float (value));
403       break;
404
405     case PROP_REORDERABLE:
406       gtk_tree_view_column_set_reorderable (tree_column,
407                                             g_value_get_boolean (value));
408       break;
409
410     case PROP_SORT_INDICATOR:
411       gtk_tree_view_column_set_sort_indicator (tree_column,
412                                                g_value_get_boolean (value));
413       break;
414
415     case PROP_SORT_ORDER:
416       gtk_tree_view_column_set_sort_order (tree_column,
417                                            g_value_get_enum (value));
418       break;
419       
420     default:
421       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
422       break;
423     }
424 }
425
426 static void
427 gtk_tree_view_column_get_property (GObject         *object,
428                                    guint            prop_id,
429                                    GValue          *value,
430                                    GParamSpec      *pspec)
431 {
432   GtkTreeViewColumn *tree_column;
433
434   tree_column = GTK_TREE_VIEW_COLUMN (object);
435
436   switch (prop_id)
437     {
438     case PROP_VISIBLE:
439       g_value_set_boolean (value,
440                            gtk_tree_view_column_get_visible (tree_column));
441       break;
442
443     case PROP_RESIZABLE:
444       g_value_set_boolean (value,
445                            gtk_tree_view_column_get_resizable (tree_column));
446       break;
447
448     case PROP_WIDTH:
449       g_value_set_int (value,
450                        gtk_tree_view_column_get_width (tree_column));
451       break;
452
453     case PROP_SIZING:
454       g_value_set_enum (value,
455                         gtk_tree_view_column_get_sizing (tree_column));
456       break;
457
458     case PROP_FIXED_WIDTH:
459       g_value_set_int (value,
460                        gtk_tree_view_column_get_fixed_width (tree_column));
461       break;
462
463     case PROP_MIN_WIDTH:
464       g_value_set_int (value,
465                        gtk_tree_view_column_get_min_width (tree_column));
466       break;
467
468     case PROP_MAX_WIDTH:
469       g_value_set_int (value,
470                        gtk_tree_view_column_get_max_width (tree_column));
471       break;
472
473     case PROP_TITLE:
474       g_value_set_string (value,
475                           gtk_tree_view_column_get_title (tree_column));
476       break;
477
478     case PROP_CLICKABLE:
479       g_value_set_boolean (value,
480                            gtk_tree_view_column_get_clickable (tree_column));
481       break;
482
483     case PROP_WIDGET:
484       g_value_set_object (value,
485                           (GObject*) gtk_tree_view_column_get_widget (tree_column));
486       break;
487
488     case PROP_ALIGNMENT:
489       g_value_set_float (value,
490                          gtk_tree_view_column_get_alignment (tree_column));
491       break;
492
493     case PROP_REORDERABLE:
494       g_value_set_boolean (value,
495                            gtk_tree_view_column_get_reorderable (tree_column));
496       break;
497
498     case PROP_SORT_INDICATOR:
499       g_value_set_boolean (value,
500                            gtk_tree_view_column_get_sort_indicator (tree_column));
501       break;
502
503     case PROP_SORT_ORDER:
504       g_value_set_enum (value,
505                         gtk_tree_view_column_get_sort_order (tree_column));
506       break;
507       
508     default:
509       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
510       break;
511     }
512 }
513
514 /* Helper functions
515  */
516
517 /* Button handling code
518  */
519 static void
520 gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
521 {
522   GtkTreeView *tree_view;
523   GtkWidget *child;
524   GtkWidget *hbox;
525
526   tree_view = (GtkTreeView *) tree_column->tree_view;
527
528   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
529   g_return_if_fail (tree_column->button == NULL);
530
531   gtk_widget_push_composite_child ();
532   tree_column->button = gtk_button_new ();
533   gtk_widget_pop_composite_child ();
534
535   /* make sure we own a reference to it as well. */
536   if (tree_view->priv->header_window)
537     gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
538   gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
539   
540   gtk_signal_connect (GTK_OBJECT (tree_column->button), "realize",
541                       (GtkSignalFunc) gtk_tree_view_column_button_realize,
542                       NULL);
543
544   gtk_signal_connect (GTK_OBJECT (tree_column->button), "event",
545                       (GtkSignalFunc) gtk_tree_view_column_button_event,
546                       (gpointer) tree_column);
547   
548   gtk_signal_connect (GTK_OBJECT (tree_column->button), "clicked",
549                       (GtkSignalFunc) gtk_tree_view_column_button_clicked,
550                       (gpointer) tree_column);
551
552   tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
553
554   hbox = gtk_hbox_new (FALSE, 2);
555   tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
556
557   if (tree_column->child)
558     child = tree_column->child;
559   else
560     {
561       child = gtk_label_new (tree_column->title);
562       gtk_widget_show (child);
563     }
564
565   if (tree_column->xalign <= 0.5)
566     gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
567   else
568     gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
569
570   gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
571         
572   gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
573   gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
574
575   gtk_widget_show (hbox);
576   gtk_widget_show (tree_column->alignment);
577   gtk_tree_view_column_update_button (tree_column);
578 }
579
580 static void 
581 gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
582 {
583   GtkWidget *hbox;
584   GtkWidget *alignment;
585   GtkWidget *arrow;
586   GtkWidget *current_child;
587
588   /* Create a button if necessary */
589   if (tree_column->visible &&
590       tree_column->button == NULL &&
591       tree_column->tree_view &&
592       GTK_WIDGET_REALIZED (tree_column->tree_view))
593     gtk_tree_view_column_create_button (tree_column);
594   
595   if (! tree_column->button)
596     return;
597
598   hbox = GTK_BIN (tree_column->button)->child;
599   alignment = tree_column->alignment;
600   arrow = tree_column->arrow;
601   current_child = GTK_BIN (alignment)->child;
602
603   /* Set up the actual button */
604   gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
605                      0.5, 0.0, 0.0);
606       
607   if (tree_column->child)
608     {
609       if (current_child != tree_column->child)
610         {
611           gtk_container_remove (GTK_CONTAINER (alignment),
612                                 current_child);
613           gtk_container_add (GTK_CONTAINER (alignment),
614                              tree_column->child);
615         }
616     }
617   else 
618     {
619       if (current_child == NULL)
620         {
621           current_child = gtk_label_new (NULL);
622           gtk_widget_show (current_child);
623           gtk_container_add (GTK_CONTAINER (alignment),
624                              current_child);
625         }
626
627       g_return_if_fail (GTK_IS_LABEL (current_child));
628
629       if (tree_column->title)
630         gtk_label_set_text (GTK_LABEL (current_child),
631                             tree_column->title);
632       else
633         gtk_label_set_text (GTK_LABEL (current_child),
634                             "");
635     }
636
637   switch (tree_column->sort_order)
638     {
639     case GTK_SORT_ASCENDING:
640       gtk_arrow_set (GTK_ARROW (arrow),
641                      GTK_ARROW_DOWN,
642                      GTK_SHADOW_IN);
643       break;
644
645     case GTK_SORT_DESCENDING:
646       gtk_arrow_set (GTK_ARROW (arrow),
647                      GTK_ARROW_UP,
648                      GTK_SHADOW_IN);
649       break;
650           
651     default:
652       g_warning (G_STRLOC": bad sort order");
653       break;
654     }
655
656   /* Put arrow on the right if the text is left-or-center justified,
657        * and on the left otherwise; do this by packing boxes, so flipping
658        * text direction will reverse things
659        */
660   gtk_widget_ref (arrow);
661   gtk_container_remove (GTK_CONTAINER (hbox), arrow);
662
663   if (tree_column->xalign <= 0.5)
664     {
665       gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
666     }
667   else
668     {
669       gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
670       /* move it to the front */
671       gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
672     }
673   gtk_widget_unref (arrow);
674
675   if (tree_column->show_sort_indicator)
676     gtk_widget_show (arrow);
677   else
678     gtk_widget_hide (arrow);
679
680   /* It's always safe to hide the button.  It isn't always safe to show it, as if you show it
681    * before it's realized, it'll get the wrong window. */
682   if (tree_column->button &&
683       tree_column->tree_view != NULL &&
684       GTK_WIDGET_REALIZED (tree_column->tree_view))
685     {
686       if (tree_column->visible)
687         {
688           gtk_widget_show_now (tree_column->button);
689           if (tree_column->window)
690             {
691               if (tree_column->resizable)
692                 {
693                   gdk_window_show (tree_column->window);
694                   gdk_window_raise (tree_column->window);
695                 }
696               else
697                 {
698                   gdk_window_hide (tree_column->window);
699                 }
700             }
701         }
702       else
703         {
704           gtk_widget_hide (tree_column->button);
705           if (tree_column->window)
706             gdk_window_hide (tree_column->window);
707         }
708     }
709   
710   if (tree_column->reorderable || tree_column->clickable)
711     {
712       GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
713     }
714   else
715     {
716       GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
717       if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
718         {
719           GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
720           if (GTK_WIDGET_TOPLEVEL (toplevel))
721             {
722               gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
723             }
724         }
725     }
726   /* Queue a resize on the assumption that we always want to catch all changes
727    * and columns don't change all that often.
728    */
729   if (GTK_WIDGET_REALIZED (tree_column->tree_view))
730      gtk_widget_queue_resize (tree_column->tree_view);
731
732 }
733
734 /* Button signal handlers
735  */
736
737 static gint
738 gtk_tree_view_column_button_event (GtkWidget *widget,
739                                    GdkEvent  *event,
740                                    gpointer   data)
741 {
742   GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
743
744   g_return_val_if_fail (event != NULL, FALSE);
745
746   if (event->type == GDK_BUTTON_PRESS &&
747       column->reorderable)
748     {
749       column->maybe_reordered = TRUE;
750       gdk_window_get_pointer (widget->window,
751                               &column->drag_x,
752                               &column->drag_y,
753                               NULL);
754       gtk_widget_grab_focus (widget);
755     }
756
757   if (event->type == GDK_BUTTON_RELEASE &&
758       column->maybe_reordered)
759     column->maybe_reordered = FALSE;
760
761   if (event->type == GDK_MOTION_NOTIFY &&
762       (column->maybe_reordered) &&
763       (gtk_drag_check_threshold (widget,
764                                  column->drag_x,
765                                  column->drag_y,
766                                  (gint) ((GdkEventMotion *)event)->x,
767                                  (gint) ((GdkEventMotion *)event)->y)))
768     {
769       column->maybe_reordered = FALSE;
770       _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
771       return TRUE;
772     }
773   if (column->clickable == FALSE)
774     {
775       switch (event->type)
776         {
777         case GDK_BUTTON_PRESS:
778         case GDK_2BUTTON_PRESS:
779         case GDK_3BUTTON_PRESS:
780         case GDK_MOTION_NOTIFY:
781         case GDK_BUTTON_RELEASE:
782         case GDK_ENTER_NOTIFY:
783         case GDK_LEAVE_NOTIFY:
784           return TRUE;
785         default:
786           return FALSE;
787         }
788     }
789   return FALSE;
790 }
791
792 static void
793 gtk_tree_view_column_button_realize (GtkWidget *widget, gpointer data)
794 {
795   gdk_window_set_events (widget->window, gdk_window_get_events (widget->window) | GDK_POINTER_MOTION_MASK);
796 }
797
798 static void
799 gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
800 {
801   g_signal_emit_by_name (G_OBJECT (data), "clicked");
802 }
803
804 static void
805 gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
806                                          GtkTreeViewColumn *column)
807 {
808   gint sort_column_id;
809   GtkSortType order;
810
811   if (gtk_tree_sortable_get_sort_column_id (sortable,
812                                             &sort_column_id,
813                                             &order))
814     {
815       if (sort_column_id == column->sort_column_id)
816         {
817           gtk_tree_view_column_set_sort_indicator (column, TRUE);
818           gtk_tree_view_column_set_sort_order (column, order);
819         }
820       else
821         {
822           gtk_tree_view_column_set_sort_indicator (column, FALSE);
823         }
824     }
825   else
826     {
827       gtk_tree_view_column_set_sort_indicator (column, FALSE);
828     }
829 }
830
831 static void
832 gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
833                            gpointer           data)
834 {
835   gint sort_column_id;
836   GtkSortType order;
837   gboolean has_sort_column;
838   gboolean has_default_sort_func;
839
840   g_return_if_fail (tree_column->tree_view != NULL);
841
842   has_sort_column =
843     gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
844                                           &sort_column_id,
845                                           &order);
846   has_default_sort_func =
847     gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model));
848
849   if (has_sort_column &&
850       sort_column_id == tree_column->sort_column_id)
851     {
852       if (order == GTK_SORT_ASCENDING)
853         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
854                                               tree_column->sort_column_id,
855                                               GTK_SORT_DESCENDING);
856       else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
857         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
858                                               GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
859                                               GTK_SORT_ASCENDING);
860       else
861         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
862                                               tree_column->sort_column_id,
863                                               GTK_SORT_ASCENDING);
864     }
865   else
866     {
867       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
868                                             tree_column->sort_column_id,
869                                             GTK_SORT_ASCENDING);
870     }
871 }
872
873
874 static void
875 gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
876 {
877   GtkTreeModel *model;
878
879   if (tree_column->tree_view == NULL)
880     return;
881
882   model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
883
884   if (model == NULL)
885     return;
886
887   if (GTK_IS_TREE_SORTABLE (model) &&
888       tree_column->sort_column_id != -1)
889     {
890       gint real_sort_column_id;
891       GtkSortType real_order;
892
893       if (tree_column->sort_column_changed_signal == 0)
894         tree_column->sort_column_changed_signal =
895           g_signal_connect (G_OBJECT (model), "sort_column_changed",
896                             GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed),
897                             tree_column);
898       
899       if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
900                                                 &real_sort_column_id,
901                                                 &real_order) &&
902           (real_sort_column_id == tree_column->sort_column_id))
903         {
904           gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
905           gtk_tree_view_column_set_sort_order (tree_column, real_order);
906
907           return;
908         }
909     }
910 }
911
912
913 /* Exported Private Functions.
914  * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
915  */
916
917 void
918 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
919 {
920   GtkTreeView *tree_view;
921   GdkWindowAttr attr;
922   guint attributes_mask;
923
924   tree_view = (GtkTreeView *)column->tree_view;
925
926   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
927   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
928   g_return_if_fail (tree_view->priv->header_window != NULL);
929   g_return_if_fail (column->button != NULL);
930
931   gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
932
933   if (column->visible)
934     gtk_widget_show (column->button);
935
936   attr.window_type = GDK_WINDOW_CHILD;
937   attr.wclass = GDK_INPUT_ONLY;
938   attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
939   attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
940   attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
941   attr.event_mask = (GDK_BUTTON_PRESS_MASK |
942                      GDK_BUTTON_RELEASE_MASK |
943                      GDK_POINTER_MOTION_MASK |
944                      GDK_POINTER_MOTION_HINT_MASK |
945                      GDK_KEY_PRESS_MASK);
946   attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
947   attr.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
948
949   attr.y = 0;
950   attr.width = TREE_VIEW_DRAG_WIDTH;
951   attr.height = tree_view->priv->header_height;
952
953   attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
954           
955   column->window = gdk_window_new (tree_view->priv->header_window,
956                                    &attr, attributes_mask);
957   gdk_window_set_user_data (column->window, tree_view);
958
959   gtk_tree_view_column_update_button (column);
960
961   gdk_cursor_unref (attr.cursor);
962 }
963
964 void
965 _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
966 {
967   g_return_if_fail (column != NULL);
968   g_return_if_fail (column->window != NULL);
969
970   gdk_window_set_user_data (column->window, NULL);
971   gdk_window_destroy (column->window);
972   column->window = NULL;
973 }
974
975 void
976 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
977                                      GtkTreeView       *tree_view)
978 {
979   g_assert (column->tree_view == NULL);
980
981   column->tree_view = GTK_WIDGET (tree_view);
982   gtk_tree_view_column_create_button (column);
983
984   column->property_changed_signal =
985           g_signal_connect_swapped (GTK_OBJECT (tree_view),
986                                     "notify::model",
987                                     GTK_SIGNAL_FUNC (gtk_tree_view_column_setup_sort_column_id_callback),
988                                     column);
989
990   gtk_tree_view_column_setup_sort_column_id_callback (column);
991 }
992
993 void
994 _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
995 {
996   if (column->tree_view && column->button)
997     {
998       gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
999     }
1000   if (column->property_changed_signal)
1001     {
1002       g_signal_handler_disconnect (G_OBJECT (column->tree_view), column->property_changed_signal);
1003       column->property_changed_signal = 0;
1004     }
1005
1006   if (column->sort_column_changed_signal)
1007     {
1008       g_signal_handler_disconnect (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view))),
1009                                    column->sort_column_changed_signal);
1010       column->sort_column_changed_signal = 0;
1011     }
1012
1013   column->tree_view = NULL;
1014   column->button = NULL;
1015 }
1016
1017 /* Public Functions */
1018
1019
1020 /**
1021  * gtk_tree_view_column_new:
1022  * 
1023  * Creates a new #GtkTreeViewColumn.
1024  * 
1025  * Return value: A newly created #GtkTreeViewColumn.
1026  **/
1027 GtkTreeViewColumn *
1028 gtk_tree_view_column_new (void)
1029 {
1030   GtkTreeViewColumn *tree_column;
1031
1032   tree_column = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
1033
1034   return tree_column;
1035 }
1036
1037 /**
1038  * gtk_tree_view_column_new_with_attributes:
1039  * @title: The title to set the header to.
1040  * @cell: The #GtkCellRenderer.
1041  * @Varargs: A %NULL-terminated list of attributes.
1042  * 
1043  * Creates a new #GtkTreeViewColumn with a number of default values.  This is
1044  * equivalent to calling gtk_tree_view_column_set_title(),
1045  * gtk_tree_view_column_pack_start(), and
1046  * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
1047  * 
1048  * Return value: A newly created #GtkTreeViewColumn.
1049  **/
1050 GtkTreeViewColumn *
1051 gtk_tree_view_column_new_with_attributes (const gchar     *title,
1052                                           GtkCellRenderer *cell,
1053                                           ...)
1054 {
1055   GtkTreeViewColumn *retval;
1056   va_list args;
1057
1058   retval = gtk_tree_view_column_new ();
1059
1060   gtk_tree_view_column_set_title (retval, title);
1061   gtk_tree_view_column_pack_start (retval, cell, TRUE);
1062
1063   va_start (args, cell);
1064   gtk_tree_view_column_set_attributesv (retval, cell, args);
1065   va_end (args);
1066
1067   return retval;
1068 }
1069
1070 static GtkTreeViewColumnCellInfo *
1071 gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
1072                                     GtkCellRenderer   *cell_renderer)
1073 {
1074   GList *list;
1075   for (list = tree_column->cell_list; list; list = list->next)
1076     if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer)
1077       return (GtkTreeViewColumnCellInfo *) list->data;
1078   return NULL;
1079 }
1080
1081
1082 /**
1083  * gtk_tree_view_column_pack_start:
1084  * @tree_column: A #GtkTreeViewColumn.
1085  * @cell: The #GtkCellRenderer. 
1086  * @expand: %TRUE if @cell is to be given extra space allocated to box.
1087  * 
1088  **/
1089 void
1090 gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
1091                                  GtkCellRenderer   *cell,
1092                                  gboolean           expand)
1093 {
1094   GtkTreeViewColumnCellInfo *cell_info;
1095
1096   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1097   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1098   g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1099
1100   g_object_ref (G_OBJECT (cell));
1101   gtk_object_sink (GTK_OBJECT (cell));
1102
1103   cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1104   cell_info->cell = cell;
1105   cell_info->expand = expand ? TRUE : FALSE;
1106   cell_info->pack = GTK_PACK_START;
1107   cell_info->has_focus = 0;
1108   cell_info->attributes = NULL;
1109
1110   tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1111 }
1112
1113 void
1114 gtk_tree_view_column_pack_end (GtkTreeViewColumn  *tree_column,
1115                                GtkCellRenderer    *cell,
1116                                gboolean            expand)
1117 {
1118   GtkTreeViewColumnCellInfo *cell_info;
1119
1120   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1121   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1122   g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1123
1124   g_object_ref (G_OBJECT (cell));
1125   gtk_object_sink (GTK_OBJECT (cell));
1126
1127   cell_info = g_new (GtkTreeViewColumnCellInfo, 1);
1128   cell_info->cell = cell;
1129   cell_info->expand = expand ? TRUE : FALSE;
1130   cell_info->pack = GTK_PACK_END;
1131   cell_info->has_focus = 0;
1132   cell_info->attributes = NULL;
1133
1134   tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1135 }
1136
1137
1138 /**
1139  * gtk_tree_view_column_clear:
1140  * @tree_column: A #GtkTreeViewColumn
1141  * 
1142  * Unsets all the mappings on all renderers on the @tree_column.
1143  **/
1144 void
1145 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1146 {
1147   GList *list;
1148   g_return_if_fail (tree_column != NULL);
1149
1150   for (list = tree_column->cell_list; list; list = list->next)
1151     {
1152       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1153
1154       g_object_unref (G_OBJECT (info->cell));
1155       gtk_tree_view_column_clear_attributes (tree_column, info->cell);
1156       g_free (info);
1157     }
1158
1159   g_list_free (tree_column->cell_list);
1160   tree_column->cell_list = NULL;
1161 }
1162
1163 /**
1164  * gtk_tree_view_column_get_cell_renderers:
1165  * @tree_column: A #GtkTreeViewColumn
1166  * 
1167  * Returns a newly-allocated #GList of all the cell renderers in the column, 
1168  * in no particular order.  The list must be freed with g_list_free().
1169  * 
1170  * Return value: A list of #GtkCellRenderers
1171  **/
1172 GList *
1173 gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
1174 {
1175   GList *retval = NULL, *list;
1176
1177   g_return_val_if_fail (tree_column != NULL, NULL);
1178
1179   for (list = tree_column->cell_list; list; list = list->next)
1180     {
1181       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1182
1183       retval = g_list_append (retval, info->cell);
1184     }
1185
1186   return retval;
1187 }
1188
1189 /**
1190  * gtk_tree_view_column_add_attribute:
1191  * @tree_column: A #GtkTreeViewColumn.
1192  * @cell_renderer: the #GtkCellRenderer to set attributes on
1193  * @attribute: An attribute on the renderer
1194  * @column: The column position on the model to get the attribute from.
1195  * 
1196  * Adds an attribute mapping to the list in @tree_column.  The @column is the
1197  * column of the model to get a value from, and the @attribute is the
1198  * parameter on @cell_renderer to be set from the value. So for example
1199  * if column 2 of the model contains strings, you could have the
1200  * "text" attribute of a #GtkCellRendererText get its values from
1201  * column 2.
1202  **/
1203 void
1204 gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1205                                     GtkCellRenderer   *cell_renderer,
1206                                     const gchar       *attribute,
1207                                     gint               column)
1208 {
1209   GtkTreeViewColumnCellInfo *info;
1210
1211   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1212   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1213   g_return_if_fail (info != NULL);
1214
1215   info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
1216   info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
1217
1218   if (tree_column->tree_view)
1219     gtk_tree_view_column_cell_set_dirty (tree_column);
1220
1221 }
1222
1223 static void
1224 gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
1225                                       GtkCellRenderer   *cell_renderer,
1226                                       va_list            args)
1227 {
1228   gchar *attribute;
1229   gint column;
1230
1231   attribute = va_arg (args, gchar *);
1232
1233   gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1234   
1235   while (attribute != NULL)
1236     {
1237       column = va_arg (args, gint);
1238       gtk_tree_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1239       attribute = va_arg (args, gchar *);
1240     }
1241 }
1242
1243 /**
1244  * gtk_tree_view_column_set_attributes:
1245  * @tree_column: A #GtkTreeViewColumn.
1246  * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1247  * @Varargs: A %NULL-terminated list of attributes.
1248  * 
1249  * Sets the attributes in the list as the attributes of @tree_column.
1250  * The attributes should be in attribute/column order, as in
1251  * gtk_tree_view_column_add_attribute(). All existing attributes
1252  * are removed, and replaced with the new attributes.
1253  **/
1254 void
1255 gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column,
1256                                      GtkCellRenderer   *cell_renderer,
1257                                      ...)
1258 {
1259   va_list args;
1260
1261   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1262   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1263   g_return_if_fail (gtk_tree_view_column_get_cell_info (tree_column, cell_renderer));
1264
1265   va_start (args, cell_renderer);
1266   gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args);
1267   va_end (args);
1268 }
1269
1270
1271 /**
1272  * gtk_tree_view_column_set_cell_data_func:
1273  * @tree_column: A #GtkTreeViewColumn
1274  * @cell_renderer: A #GtkCellRenderer
1275  * @func: The #GtkTreeViewColumnFunc to use. 
1276  * @func_data: The user data for @func.
1277  * @destroy: The destroy notification for @func_data
1278  * 
1279  * Sets the #GtkTreeViewColumnFunc to use for the column.  This
1280  * function is used instead of the standard attributes mapping for
1281  * setting the column value, and should set the value of @tree_column's
1282  * cell renderer as appropriate.  @func may be %NULL to remove an
1283  * older one.
1284  **/
1285 void
1286 gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn   *tree_column,
1287                                          GtkCellRenderer     *cell_renderer,
1288                                          GtkTreeCellDataFunc  func,
1289                                          gpointer             func_data,
1290                                          GtkDestroyNotify     destroy)
1291 {
1292   GtkTreeViewColumnCellInfo *info;
1293
1294   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1295   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1296   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1297
1298   g_return_if_fail (info != NULL);
1299
1300   if (func == info->func &&
1301       func_data == info->func_data &&
1302       destroy == info->destroy)
1303     return;
1304
1305   if (info->func_data && info->destroy)
1306     (info->destroy) (info->func_data);
1307
1308   info->func = func;
1309   info->func_data = func_data;
1310   info->destroy = destroy;
1311
1312   if (tree_column->tree_view)
1313     gtk_tree_view_column_cell_set_dirty (tree_column);
1314 }
1315
1316
1317 /**
1318  * gtk_tree_view_column_clear_attributes:
1319  * @tree_column: a #GtkTreeViewColumn
1320  * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1321  * 
1322  * Clears all existing attributes previously set with
1323  * gtk_tree_view_column_set_attributes().
1324  **/
1325 void
1326 gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
1327                                        GtkCellRenderer   *cell_renderer)
1328 {
1329   GtkTreeViewColumnCellInfo *info;
1330   GSList *list;
1331
1332   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1333   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1334   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1335
1336   list = info->attributes;
1337
1338   while (list && list->next)
1339     {
1340       g_free (list->data);
1341       list = list->next->next;
1342     }
1343   g_slist_free (info->attributes);
1344   info->attributes = NULL;
1345
1346   if (tree_column->tree_view)
1347     gtk_tree_view_column_cell_set_dirty (tree_column);
1348 }
1349
1350
1351 /**
1352  * gtk_tree_view_column_set_spacing:
1353  * @tree_column: A #GtkTreeViewColumn.
1354  * @spacing: distance between cell renderers in pixels.
1355  * 
1356  * Sets the spacing field of @tree_column, which is the number of pixels to
1357  * place between cell renderers packed into it.
1358  **/
1359 void
1360 gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
1361                                   gint               spacing)
1362 {
1363   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1364   g_return_if_fail (spacing >= 0);
1365
1366   if (tree_column->spacing == spacing)
1367     return;
1368
1369   tree_column->spacing = spacing;
1370   if (tree_column->tree_view)
1371     gtk_tree_view_column_cell_set_dirty (tree_column);
1372 }
1373
1374 /**
1375  * gtk_tree_view_column_get_spacing:
1376  * @tree_column: A #GtkTreeViewColumn.
1377  * 
1378  * Returns the spacing of @tree_column.
1379  * 
1380  * Return value: the spacing of @tree_column.
1381  **/
1382 gint
1383 gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column)
1384 {
1385   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1386
1387   return tree_column->spacing;
1388 }
1389
1390 /* Options for manipulating the columns */
1391
1392 /**
1393  * gtk_tree_view_column_set_visible:
1394  * @tree_column: A #GtkTreeViewColumn.
1395  * @visible: %TRUE if the @tree_column is visible.
1396  * 
1397  * Sets the visibility of @tree_column.
1398  **/
1399 void
1400 gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
1401                                   gboolean           visible)
1402 {
1403   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1404
1405   visible = !! visible;
1406   
1407   if (tree_column->visible == visible)
1408     return;
1409
1410   tree_column->visible = visible;
1411
1412   gtk_tree_view_column_update_button (tree_column);
1413   g_object_notify (G_OBJECT (tree_column), "visible");
1414 }
1415
1416 /**
1417  * gtk_tree_view_column_get_visible:
1418  * @tree_column: A #GtkTreeViewColumn.
1419  * 
1420  * Returns %TRUE if @tree_column is visible.
1421  * 
1422  * Return value: whether the column is visible or not.  If it is visible, then
1423  * the tree will show the column.
1424  **/
1425 gboolean
1426 gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
1427 {
1428   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1429
1430   return tree_column->visible;
1431 }
1432
1433 void
1434 gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
1435                                     gboolean           resizable)
1436 {
1437   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1438
1439   resizable = !! resizable;
1440
1441   if (tree_column->resizable == resizable)
1442     return;
1443
1444   tree_column->resizable = resizable;
1445
1446   if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1447     gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1448
1449   gtk_tree_view_column_update_button (tree_column);
1450
1451   g_object_notify (G_OBJECT (tree_column), "resizable");
1452 }
1453
1454 gboolean
1455 gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column)
1456 {
1457   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1458
1459   return tree_column->resizable;
1460 }
1461
1462
1463 /**
1464  * gtk_tree_view_column_set_sizing:
1465  * @tree_column: A #GtkTreeViewColumn.
1466  * @type: The #GtkTreeViewColumnSizing.
1467  * 
1468  * Sets the growth behavior of @tree_column to @type.
1469  **/
1470 void
1471 gtk_tree_view_column_set_sizing (GtkTreeViewColumn       *tree_column,
1472                                  GtkTreeViewColumnSizing  type)
1473 {
1474   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1475
1476   if (type == tree_column->column_type)
1477     return;
1478
1479   if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1480     gtk_tree_view_column_set_resizable (tree_column, FALSE);
1481
1482 #if 0
1483   /* I was clearly on crack when I wrote this.  I'm not sure what's supposed to
1484    * be below so I'll leave it until I figure it out.
1485    */
1486   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE &&
1487       tree_column->requested_width != -1)
1488     {
1489       gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width);
1490     }
1491 #endif
1492   tree_column->column_type = type;
1493
1494   gtk_tree_view_column_update_button (tree_column);
1495
1496   g_object_notify (G_OBJECT (tree_column), "sizing");
1497 }
1498
1499 /**
1500  * gtk_tree_view_column_get_sizing:
1501  * @tree_column: A #GtkTreeViewColumn.
1502  * 
1503  * Returns the current type of @tree_column.
1504  * 
1505  * Return value: The type of @tree_column.
1506  **/
1507 GtkTreeViewColumnSizing
1508 gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column)
1509 {
1510   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1511
1512   return tree_column->column_type;
1513 }
1514
1515 /**
1516  * gtk_tree_view_column_get_width:
1517  * @tree_column: A #GtkTreeViewColumn.
1518  * 
1519  * Returns the current size of @tree_column in pixels.
1520  * 
1521  * Return value: The current width of @tree_column.
1522  **/
1523 gint
1524 gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column)
1525 {
1526   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1527
1528   return tree_column->width;
1529 }
1530
1531 /**
1532  * gtk_tree_view_column_set_fixed_width:
1533  * @tree_column: A #GtkTreeViewColumn.
1534  * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1535  * 
1536  * Sets the size of the column in pixels.  This is meaningful only if the sizing
1537  * type is #GTK_TREE_VIEW_COLUMN_FIXED.  In this case, the value is discarded
1538  * as the size of the column is based on the calculated width of the column. The
1539  * width is clamped to the min/max width for the column.
1540  **/
1541 void
1542 gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
1543                                       gint               fixed_width)
1544 {
1545   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1546   g_return_if_fail (fixed_width > 0);
1547
1548   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1549     return;
1550
1551   tree_column->fixed_width = fixed_width;
1552
1553   if (tree_column->tree_view &&
1554       GTK_WIDGET_REALIZED (tree_column->tree_view) &&
1555       tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1556     {
1557       gtk_widget_queue_resize (tree_column->tree_view);
1558     }
1559 }
1560
1561 /**
1562  * gtk_tree_view_column_get_fixed_width:
1563  * @tree_column: a #GtkTreeViewColumn
1564  * 
1565  * Gets the fixed width of the column.  This value is only meaning may not be
1566  * the actual width of the column on the screen, just what is requested.
1567  * 
1568  * Return value: the fixed width of the column
1569  **/
1570 gint
1571 gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column)
1572 {
1573   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1574
1575   return tree_column->fixed_width;
1576 }
1577
1578 /**
1579  * gtk_tree_view_column_set_min_width:
1580  * @tree_column: A #GtkTreeViewColumn.
1581  * @min_width: The minimum width of the column in pixels, or -1.
1582  * 
1583  * Sets the minimum width of the @tree_column.  If @min_width is -1, then the
1584  * minimum width is unset.
1585  **/
1586 void
1587 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
1588                                     gint               min_width)
1589 {
1590   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1591   g_return_if_fail (min_width >= -1);
1592
1593   if (min_width == tree_column->min_width)
1594     return;
1595
1596   if (tree_column->visible &&
1597       tree_column->tree_view != NULL &&
1598       GTK_WIDGET_REALIZED (tree_column->tree_view))
1599     {
1600       if (min_width > tree_column->width)
1601         gtk_widget_queue_resize (tree_column->tree_view);
1602     }
1603
1604   tree_column->min_width = min_width;
1605   if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1606     {
1607       tree_column->max_width = min_width;
1608       g_object_notify (G_OBJECT (tree_column), "max_width");
1609     }
1610   g_object_notify (G_OBJECT (tree_column), "min_width");
1611 }
1612
1613 /**
1614  * gtk_tree_view_column_get_min_width:
1615  * @tree_column: A #GtkTreeViewColumn.
1616  * 
1617  * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1618  * width is set.
1619  * 
1620  * Return value: The minimum width of the @tree_column.
1621  **/
1622 gint
1623 gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
1624 {
1625   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1626
1627   return tree_column->min_width;
1628 }
1629
1630 /**
1631  * gtk_tree_view_column_set_max_width:
1632  * @tree_column: A #GtkTreeViewColumn.
1633  * @max_width: The maximum width of the column in pixels, or -1.
1634  * 
1635  * Sets the maximum width of the @tree_column.  If @max_width is -1, then the
1636  * maximum width is unset.  Note, the column can actually be wider than max
1637  * width if it's the last column in a view.  In this case, the column expands to
1638  * fill any extra space.
1639  **/
1640 void
1641 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
1642                                     gint               max_width)
1643 {
1644   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1645   g_return_if_fail (max_width >= -1);
1646
1647   if (max_width == tree_column->max_width)
1648     return;
1649
1650   if (tree_column->visible &&
1651       tree_column->tree_view != NULL &&
1652       GTK_WIDGET_REALIZED (tree_column->tree_view))
1653     {
1654       if (max_width != -1 && max_width < tree_column->width)
1655         gtk_widget_queue_resize (tree_column->tree_view);
1656     }
1657
1658   tree_column->max_width = max_width;
1659   if (max_width != -1 && max_width < tree_column->min_width)
1660     {
1661       tree_column->min_width = max_width;
1662       g_object_notify (G_OBJECT (tree_column), "min_width");
1663     }
1664   g_object_notify (G_OBJECT (tree_column), "max_width");
1665 }
1666
1667 /**
1668  * gtk_tree_view_column_get_max_width:
1669  * @tree_column: A #GtkTreeViewColumn.
1670  * 
1671  * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
1672  * width is set.
1673  * 
1674  * Return value: The maximum width of the @tree_column.
1675  **/
1676 gint
1677 gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
1678 {
1679   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1680
1681   return tree_column->max_width;
1682 }
1683
1684 /**
1685  * gtk_tree_view_column_clicked:
1686  * @tree_column: a #GtkTreeViewColumn
1687  * 
1688  * Emits the "clicked" signal on the column.  This function will only work if
1689  * @tree_column is clickable.
1690  **/
1691 void
1692 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
1693 {
1694   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1695
1696   if (tree_column->visible &&
1697       tree_column->button &&
1698       tree_column->clickable)
1699     gtk_button_clicked (GTK_BUTTON (tree_column->button));
1700 }
1701
1702 /**
1703  * gtk_tree_view_column_set_title:
1704  * @tree_column: A #GtkTreeViewColumn.
1705  * @title: The title of the @tree_column.
1706  * 
1707  * Sets the title of the @tree_column.  If a custom widget has been set, then
1708  * this value is ignored.
1709  **/
1710 void
1711 gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column,
1712                                 const gchar       *title)
1713 {
1714   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1715
1716   g_free (tree_column->title);
1717   if (title)
1718     tree_column->title = g_strdup (title);
1719   else
1720     tree_column->title = NULL;
1721
1722   gtk_tree_view_column_update_button (tree_column);
1723   g_object_notify (G_OBJECT (tree_column), "title");
1724 }
1725
1726 /**
1727  * gtk_tree_view_column_get_title:
1728  * @tree_column: A #GtkTreeViewColumn.
1729  * 
1730  * Returns the title of the widget.  This value should not be modified.
1731  * 
1732  * Return value: the title of the column.
1733  **/
1734 G_CONST_RETURN gchar *
1735 gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column)
1736 {
1737   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1738
1739   return tree_column->title;
1740 }
1741
1742 /**
1743  * gtk_tree_view_column_set_clickable:
1744  * @tree_column: A #GtkTreeViewColumn.
1745  * @clickable: %TRUE if the header is active.
1746  * 
1747  * Sets the header to be active if @active is %TRUE.  When the header is active,
1748  * then it can take keyboard focus, and can be clicked.
1749  **/
1750 void
1751 gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
1752                                     gboolean           clickable)
1753 {
1754   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1755
1756   clickable = !! clickable;
1757   if (tree_column->clickable == clickable)
1758     return;
1759
1760   tree_column->clickable = clickable;
1761   gtk_tree_view_column_update_button (tree_column);
1762   g_object_notify (G_OBJECT (tree_column), "clickable");
1763 }
1764
1765 /**
1766  * gtk_tree_view_column_get_clickable:
1767  * @tree_column: a #GtkTreeViewColumn
1768  * 
1769  * Returns %TRUE if the user can click on the header for the column.
1770  * 
1771  * Return value: %TRUE if user can click the column header.
1772  **/
1773 gboolean
1774 gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
1775 {
1776   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1777
1778   return tree_column->clickable;
1779 }
1780
1781 /**
1782  * gtk_tree_view_column_set_widget:
1783  * @tree_column: A #GtkTreeViewColumn.
1784  * @widget: A child #GtkWidget, or %NULL.
1785  * 
1786  * Sets the widget in the header to be @widget.  If widget is %NULL, then the
1787  * header button is set with a #GtkLabel set to the title of @tree_column.
1788  **/
1789 void
1790 gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column,
1791                                  GtkWidget         *widget)
1792 {
1793   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1794   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
1795
1796   if (widget)
1797     {
1798       gtk_object_ref (GTK_OBJECT (widget));
1799       gtk_object_sink (GTK_OBJECT (widget));
1800     }
1801
1802   if (tree_column->child)      
1803     gtk_object_unref (GTK_OBJECT (tree_column->child));
1804
1805   tree_column->child = widget;
1806   gtk_tree_view_column_update_button (tree_column);
1807   g_object_notify (G_OBJECT (tree_column), "widget");
1808 }
1809
1810 /**
1811  * gtk_tree_view_column_get_widget:
1812  * @tree_column: A #GtkTreeViewColumn.
1813  * 
1814  * Returns the #GtkWidget in the button in the column header.  If a custom
1815  * widget has not been set, then this will be a #GtkAlignment with a #GtkLabel
1816  * in it.
1817  * 
1818  * Return value: The #GtkWidget in the column header.
1819  **/
1820 GtkWidget *
1821 gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column)
1822 {
1823   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1824
1825   return tree_column->child;
1826 }
1827
1828 /**
1829  * gtk_tree_view_column_set_alignment:
1830  * @tree_column: A #GtkTreeViewColumn.
1831  * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
1832  * 
1833  * Sets the alignment of the title or custom widget inside the column header.
1834  * The alignment determines its location inside the button -- 0.0 for left, 0.5
1835  * for center, 1.0 for right.
1836  **/
1837 void
1838 gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
1839                                     gfloat             xalign)
1840 {
1841   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1842
1843   xalign = CLAMP (xalign, 0.0, 1.0);
1844
1845   if (tree_column->xalign == xalign)
1846     return;
1847
1848   tree_column->xalign = xalign;
1849   gtk_tree_view_column_update_button (tree_column);
1850   g_object_notify (G_OBJECT (tree_column), "alignment");
1851 }
1852
1853 /**
1854  * gtk_tree_view_column_get_alignment:
1855  * @tree_column: A #GtkTreeViewColumn.
1856  * 
1857  * Returns the current x alignment of @tree_column.  This value can range
1858  * between 0.0 and 1.0.
1859  * 
1860  * Return value: The current alignent of @tree_column.
1861  **/
1862 gfloat
1863 gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
1864 {
1865   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0.5);
1866
1867   return tree_column->xalign;
1868 }
1869
1870 void
1871 gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column,
1872                                       gboolean           reorderable)
1873 {
1874   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1875
1876   /*  if (reorderable)
1877       gtk_tree_view_column_set_clickable (tree_column, TRUE);*/
1878
1879   if (tree_column->reorderable == (reorderable?TRUE:FALSE))
1880     return;
1881
1882   tree_column->reorderable = (reorderable?TRUE:FALSE);
1883   gtk_tree_view_column_update_button (tree_column);
1884   g_object_notify (G_OBJECT (tree_column), "reorderable");
1885 }
1886
1887 gboolean
1888 gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column)
1889 {
1890   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1891
1892   return tree_column->reorderable;
1893 }
1894
1895
1896 /**
1897  * gtk_tree_view_column_set_sort_column_id:
1898  * @tree_column: a #GtkTreeViewColumn
1899  * @sort_column_id: The @sort_column_id of the model to sort on.
1900  * 
1901  * Sets the logical @sort_column_id that this column sorts on when this column 
1902  * is selected for sorting.  Doing so makes the column header clickable.
1903  **/
1904 void
1905 gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
1906                                          gint               sort_column_id)
1907 {
1908   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1909   g_return_if_fail (sort_column_id >= 0);
1910
1911   if (tree_column->sort_column_id == sort_column_id)
1912     return;
1913
1914   tree_column->sort_column_id = sort_column_id;
1915
1916   /* Handle unsetting the id */
1917   if (sort_column_id == -1)
1918     {
1919       if (tree_column->sort_clicked_signal)
1920         {
1921           g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_clicked_signal);
1922           tree_column->sort_clicked_signal = 0;
1923         }
1924
1925       if (tree_column->sort_column_changed_signal)
1926         {
1927           g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_column_changed_signal);
1928           tree_column->sort_column_changed_signal = 0;
1929         }
1930
1931       gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
1932       gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
1933       return;
1934     }
1935
1936   gtk_tree_view_column_set_clickable (tree_column, TRUE);
1937
1938   if (! tree_column->sort_clicked_signal)
1939     tree_column->sort_clicked_signal = g_signal_connect (G_OBJECT (tree_column),
1940                                                          "clicked",
1941                                                          G_CALLBACK (gtk_tree_view_column_sort),
1942                                                          NULL);
1943
1944   gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
1945 }
1946
1947 /**
1948  * gtk_tree_view_column_get_sort_column_id:
1949  * @tree_column: a #GtkTreeViewColumn
1950  *
1951  * Gets the logical @sort_column_id that the model sorts on when this
1952  * column is selected for sorting. See gtk_tree_view_column_set_sort_column_id().
1953  *
1954  * Return value: the current @sort_column_id for this column, or -1 if
1955  *               this column can't be used for sorting.
1956  **/
1957 gint
1958 gtk_tree_view_column_get_sort_column_id (GtkTreeViewColumn *tree_column)
1959 {
1960   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1961
1962   return tree_column->sort_column_id;
1963 }
1964
1965 /**
1966  * gtk_tree_view_column_set_sort_indicator:
1967  * @tree_column: a #GtkTreeViewColumn
1968  * @setting: %TRUE to display an indicator that the column is sorted
1969  *
1970  * Call this function with a @setting of %TRUE to display an arrow in
1971  * the header button indicating the column is sorted. Call
1972  * gtk_tree_view_column_set_sort_order() to change the direction of
1973  * the arrow.
1974  * 
1975  **/
1976 void
1977 gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn     *tree_column,
1978                                          gboolean               setting)
1979 {
1980   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1981
1982   setting = setting != FALSE;
1983
1984   if (setting == tree_column->show_sort_indicator)
1985     return;
1986
1987   tree_column->show_sort_indicator = setting;
1988   gtk_tree_view_column_update_button (tree_column);
1989   g_object_notify (G_OBJECT (tree_column), "sort_indicator");
1990 }
1991
1992 /**
1993  * gtk_tree_view_column_get_sort_indicator:
1994  * @tree_column: a #GtkTreeViewColumn
1995  * 
1996  * Gets the value set by gtk_tree_view_column_set_sort_indicator().
1997  * 
1998  * Return value: whether the sort indicator arrow is displayed
1999  **/
2000 gboolean
2001 gtk_tree_view_column_get_sort_indicator  (GtkTreeViewColumn     *tree_column)
2002 {
2003   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2004
2005   return tree_column->show_sort_indicator;
2006 }
2007
2008 /**
2009  * gtk_tree_view_column_set_sort_order:
2010  * @tree_column: a #GtkTreeViewColumn
2011  * @order: sort order that the sort indicator should indicate
2012  *
2013  * Changes the appearance of the sort indicator. 
2014  * 
2015  * This <emphasis>does not</emphasis> actually sort the model.  Use
2016  * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
2017  * support.  This function is primarily for custom sorting behavior, and should
2018  * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2019  * that. For custom models, the mechanism will vary. 
2020  * 
2021  * The sort indicator changes direction to indicate normal sort or reverse sort.
2022  * Note that you must have the sort indicator enabled to see anything when 
2023  * calling this function; see gtk_tree_view_column_set_sort_indicator().
2024  **/
2025 void
2026 gtk_tree_view_column_set_sort_order      (GtkTreeViewColumn     *tree_column,
2027                                           GtkSortType            order)
2028 {
2029   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2030
2031   if (order == tree_column->sort_order)
2032     return;
2033
2034   tree_column->sort_order = order;
2035   gtk_tree_view_column_update_button (tree_column);
2036   g_object_notify (G_OBJECT (tree_column), "sort_order");
2037 }
2038
2039 /**
2040  * gtk_tree_view_column_get_sort_order:
2041  * @tree_column: a #GtkTreeViewColumn
2042  * 
2043  * Gets the value set by gtk_tree_view_column_set_sort_order().
2044  * 
2045  * Return value: the sort order the sort indicator is indicating
2046  **/
2047 GtkSortType
2048 gtk_tree_view_column_get_sort_order      (GtkTreeViewColumn     *tree_column)
2049 {
2050   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2051
2052   return tree_column->sort_order;
2053 }
2054
2055 /**
2056  * gtk_tree_view_column_cell_set_cell_data:
2057  * @tree_column: A #GtkTreeViewColumn.
2058  * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2059  * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2060  * @is_expander: %TRUE, if the row has children
2061  * @is_expanded: %TRUE, if the row has visible children
2062  * 
2063  * Sets the cell renderer based on the @tree_model and @tree_node.  That is, for
2064  * every attribute mapping in @tree_column, it will get a value from the set
2065  * column on the @tree_node, and use that value to set the attribute on the cell
2066  * renderer.  This is used primarily by the #GtkTreeView.
2067  **/
2068 void
2069 gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column,
2070                                          GtkTreeModel      *tree_model,
2071                                          GtkTreeIter       *iter,
2072                                          gboolean           is_expander,
2073                                          gboolean           is_expanded)
2074 {
2075   GSList *list;
2076   GValue value = { 0, };
2077   GList *cell_list;
2078
2079   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2080   g_return_if_fail (tree_column->cell_list != NULL);
2081
2082   if (tree_model == NULL)
2083     return;
2084
2085   for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2086     {
2087       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data;
2088       GObject *cell = (GObject *) info->cell;
2089
2090       list = info->attributes;
2091
2092       g_object_freeze_notify (cell);
2093       g_object_set (cell, "is_expander", is_expander, "is_expanded", is_expanded, NULL);
2094
2095       while (list && list->next)
2096         {
2097           gtk_tree_model_get_value (tree_model, iter,
2098                                     GPOINTER_TO_INT (list->next->data),
2099                                     &value);
2100           g_object_set_property (cell, (gchar *) list->data, &value);
2101           g_value_unset (&value);
2102           list = list->next->next;
2103         }
2104
2105       if (info->func)
2106         (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2107       g_object_thaw_notify (G_OBJECT (info->cell));
2108     }
2109
2110 }
2111
2112 /**
2113  * gtk_tree_view_column_cell_get_size:
2114  * @tree_column: A #GtkTreeViewColumn.
2115  * @cell_area: The area a the column will be allocated, or %NULL
2116  * @x_offset: location to return x offset of cell relative to @cell_area, or %NULL
2117  * @y_offset: location to return y offset of cell relative to @cell_area, or %NULL
2118  * @width: location to return width needed to render a cell, or %NULL
2119  * @height: location to return height needed to render a cell, or %NULL
2120  * 
2121  * Obtains the width and height needed to render the column.  This is used
2122  * primarily by the #GtkTreeView.
2123  **/
2124 void
2125 gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
2126                                     GdkRectangle      *cell_area,
2127                                     gint              *x_offset,
2128                                     gint              *y_offset,
2129                                     gint              *width,
2130                                     gint              *height)
2131 {
2132   GList *list;
2133   gboolean first_cell = TRUE;
2134
2135   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2136
2137   if (height)
2138     * height = 0;
2139   if (width)
2140     * width = 0;
2141
2142   for (list = tree_column->cell_list; list; list = list->next)
2143     {
2144       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2145       gboolean visible;
2146       gint new_height = 0;
2147       gint new_width = 0;
2148       g_object_get (info->cell, "visible", &visible, NULL);
2149
2150       if (visible == FALSE)
2151         continue;
2152
2153       if (first_cell == FALSE && *width)
2154         *width += tree_column->spacing;
2155
2156       gtk_cell_renderer_get_size (info->cell,
2157                                   tree_column->tree_view,
2158                                   cell_area,
2159                                   x_offset,
2160                                   y_offset,
2161                                   &new_width,
2162                                   &new_height);
2163
2164       if (height)
2165         * height = MAX (*height, new_height);
2166       info->requested_width = MAX (info->requested_width, new_width);
2167       if (width)
2168         * width += info->requested_width;
2169       first_cell = TRUE;
2170     }
2171 }
2172
2173 /* both rendering and rendering focus are somewhat complicated, and a bit of
2174  * code.  Rather than duplicate them, we put them together to keep the code in
2175  * one place
2176  */
2177 static void
2178 gtk_tree_view_column_cell_render_or_focus (GtkTreeViewColumn *tree_column,
2179                                            GdkWindow         *window,
2180                                            GdkRectangle      *background_area,
2181                                            GdkRectangle      *cell_area,
2182                                            GdkRectangle      *expose_area,
2183                                            guint              flags,
2184                                            gboolean           render,
2185                                            GdkRectangle      *focus_rectangle)
2186 {
2187   GList *list;
2188   GdkRectangle real_cell_area;
2189   gint expand_cell_count = 0;
2190   gint full_requested_width = 0;
2191   gint extra_space;
2192   gint min_x, min_y, max_x, max_y;
2193
2194   min_x = G_MAXINT;
2195   min_y = G_MAXINT;
2196   max_x = 0;
2197   max_y = 0;
2198
2199   real_cell_area = *cell_area;
2200
2201   /* Find out how my extra space we have to allocate */
2202   for (list = tree_column->cell_list; list; list = list->next)
2203     {
2204       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2205
2206       if (! info->cell->visible)
2207         continue;
2208
2209       if (info->expand == TRUE)
2210         expand_cell_count ++;
2211       full_requested_width += info->requested_width;
2212     }
2213
2214   extra_space = cell_area->width - full_requested_width;
2215   if (extra_space < 0)
2216     extra_space = 0;
2217
2218   for (list = tree_column->cell_list; list; list = list->next)
2219     {
2220       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2221
2222       if (info->pack == GTK_PACK_END)
2223         continue;
2224
2225       if (! info->cell->visible)
2226         continue;
2227
2228       real_cell_area.width = info->requested_width +
2229         (info->expand?extra_space:0);
2230       if (render)
2231         {
2232           gtk_cell_renderer_render (info->cell,
2233                                     window,
2234                                     tree_column->tree_view,
2235                                     background_area,
2236                                     &real_cell_area,
2237                                     expose_area,
2238                                     flags);
2239         }
2240       else
2241         {
2242           gint x_offset, y_offset, width, height;
2243
2244           gtk_cell_renderer_get_size (info->cell,
2245                                       tree_column->tree_view,
2246                                       &real_cell_area,
2247                                       &x_offset, &y_offset,
2248                                       &width, &height);
2249
2250           if (min_x > (real_cell_area.x + x_offset))
2251             min_x = real_cell_area.x + x_offset;
2252           if (max_x < real_cell_area.x + x_offset + width)
2253             max_x = real_cell_area.x + x_offset + width;
2254           if (min_y > (real_cell_area.y + y_offset))
2255             min_y = real_cell_area.y + y_offset;
2256           if (max_y < real_cell_area.y + y_offset + height)
2257             max_y = real_cell_area.y + y_offset + height;
2258         }
2259       real_cell_area.x += (info->requested_width + tree_column->spacing);
2260     }
2261   for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2262     {
2263       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2264
2265       if (info->pack == GTK_PACK_START)
2266         continue;
2267
2268       if (! info->cell->visible)
2269         continue;
2270
2271       real_cell_area.width = info->requested_width +
2272         (info->expand?extra_space:0);
2273       gtk_cell_renderer_render (info->cell,
2274                                 window,
2275                                 tree_column->tree_view,
2276                                 background_area,
2277                                 &real_cell_area,
2278                                 expose_area,
2279                                 flags);
2280       real_cell_area.x += (info->requested_width + tree_column->spacing);
2281     }
2282   if (! render)
2283     {
2284       if (min_x >= max_x || min_y >= max_y)
2285         {
2286           *focus_rectangle = *cell_area;
2287           focus_rectangle->x -= 1;
2288           focus_rectangle->y -= 1;
2289           focus_rectangle->width += 2;
2290           focus_rectangle->height += 2;
2291         }
2292       else
2293         {
2294           focus_rectangle->x = min_x - 1;
2295           focus_rectangle->y = min_y - 1;
2296           focus_rectangle->width = (max_x - min_x) + 2;
2297           focus_rectangle->height = (max_y - min_y) + 2;
2298         }
2299     }
2300 }
2301
2302 /**
2303  * gtk_tree_view_column_cell_render:
2304  * @tree_column: A #GtkTreeViewColumn.
2305  * @window: a #GdkDrawable to draw to
2306  * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
2307  * @cell_area: area normally rendered by a cell renderer
2308  * @expose_area: area that actually needs updating
2309  * @flags: flags that affect rendering
2310  * 
2311  * Renders the cell contained by #tree_column. This is used primarily by the
2312  * #GtkTreeView.
2313  **/
2314 void
2315 gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
2316                                   GdkWindow         *window,
2317                                   GdkRectangle      *background_area,
2318                                   GdkRectangle      *cell_area,
2319                                   GdkRectangle      *expose_area,
2320                                   guint              flags)
2321 {
2322   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2323   g_return_if_fail (background_area != NULL);
2324   g_return_if_fail (cell_area != NULL);
2325   g_return_if_fail (expose_area != NULL);
2326
2327   gtk_tree_view_column_cell_render_or_focus (tree_column,
2328                                              window,
2329                                              background_area,
2330                                              cell_area,
2331                                              expose_area,
2332                                              flags,
2333                                              TRUE,
2334                                              NULL);
2335 }
2336
2337 gboolean
2338 _gtk_tree_view_column_cell_event (GtkTreeViewColumn  *tree_column,
2339                                   GtkCellEditable   **editable_widget,
2340                                   GdkEvent           *event,
2341                                   gchar              *path_string,
2342                                   GdkRectangle       *background_area,
2343                                   GdkRectangle       *cell_area,
2344                                   guint               flags)
2345 {
2346   gboolean visible, mode;
2347
2348   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2349
2350   g_object_get (G_OBJECT (((GtkTreeViewColumnCellInfo *) tree_column->cell_list->data)->cell),
2351                 "visible", &visible,
2352                 "mode", &mode,
2353                 NULL);
2354   if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2355     {
2356       if (gtk_cell_renderer_activate (((GtkTreeViewColumnCellInfo *) tree_column->cell_list->data)->cell,
2357                                       event,
2358                                       tree_column->tree_view,
2359                                       path_string,
2360                                       background_area,
2361                                       cell_area,
2362                                       flags))
2363         return TRUE;
2364     }
2365   else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2366     {
2367       *editable_widget = gtk_cell_renderer_start_editing (((GtkTreeViewColumnCellInfo *) tree_column->cell_list->data)->cell,
2368                                                           event,
2369                                                           tree_column->tree_view,
2370                                                           path_string,
2371                                                           background_area,
2372                                                           cell_area,
2373                                                           flags);
2374
2375       if (*editable_widget != NULL)
2376         {
2377           g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2378
2379           return TRUE;
2380         }
2381     }
2382   return FALSE;
2383 }
2384
2385
2386 gboolean
2387 gtk_tree_view_column_cell_focus (GtkTreeViewColumn *tree_column,
2388                                  gint               direction)
2389 {
2390   if (GTK_TREE_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
2391     return FALSE;
2392   return TRUE;
2393 }
2394
2395 void
2396 gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn       *tree_column,
2397                                       GdkWindow               *window,
2398                                       GdkRectangle            *background_area,
2399                                       GdkRectangle            *cell_area,
2400                                       GdkRectangle            *expose_area,
2401                                       guint                    flags)
2402 {
2403   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2404   if (tree_column->editable_widget)
2405     {
2406       /* This function is only called on the editable row when editing.
2407        */
2408
2409       gtk_paint_focus (tree_column->tree_view->style,
2410                        window,
2411                        GTK_WIDGET_STATE (tree_column->tree_view),
2412                        NULL,
2413                        tree_column->tree_view,
2414                        "treeview",
2415                        cell_area->x - 1,
2416                        cell_area->y - 1,
2417                        cell_area->width + 2,
2418                        cell_area->height + 2);
2419       
2420     }
2421   else
2422     {
2423       GdkRectangle focus_rectangle;
2424       gtk_tree_view_column_cell_render_or_focus (tree_column,
2425                                                  window,
2426                                                  background_area,
2427                                                  cell_area,
2428                                                  expose_area,
2429                                                  flags,
2430                                                  FALSE,
2431                                                  &focus_rectangle);
2432       
2433       gtk_paint_focus (tree_column->tree_view->style,
2434                        window,
2435                        GTK_WIDGET_STATE (tree_column->tree_view),
2436                        NULL,
2437                        tree_column->tree_view,
2438                        "treeview",
2439                        focus_rectangle.x,
2440                        focus_rectangle.y,
2441                        focus_rectangle.width,
2442                        focus_rectangle.height);
2443     }
2444 }
2445
2446 gboolean
2447 gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
2448 {
2449   GList *list;
2450
2451   for (list = tree_column->cell_list; list; list = list->next)
2452     {
2453       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2454
2455       if (info->cell->visible)
2456         return TRUE;
2457     }
2458
2459   return FALSE;
2460 }
2461
2462 void
2463 gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column)
2464 {
2465   GList *list;
2466
2467   for (list = tree_column->cell_list; list; list = list->next)
2468     {
2469       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2470
2471       info->requested_width = 0;
2472     }
2473   tree_column->dirty = TRUE;
2474   tree_column->requested_width = 0;
2475
2476   if (tree_column->tree_view &&
2477       GTK_WIDGET_REALIZED (tree_column->tree_view))
2478     {
2479       _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
2480       gtk_widget_queue_resize (tree_column->tree_view);
2481     }
2482 }
2483
2484 void
2485 _gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
2486                                      GtkCellEditable   *cell_editable)
2487 {
2488   g_return_if_fail (tree_column->editable_widget == NULL);
2489
2490   tree_column->editable_widget = cell_editable;
2491 }
2492
2493 void
2494 _gtk_tree_view_column_stop_editing (GtkTreeViewColumn *tree_column)
2495 {
2496   g_return_if_fail (tree_column->editable_widget != NULL);
2497
2498   tree_column->editable_widget = NULL;
2499 }