]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeviewcolumn.c
Changes to gtktreeview to better support thicker focus lines,
[~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_clicked                (GtkWidget               *widget,
96                                                                 gpointer                 data);
97
98 /* Property handlers */
99 static void gtk_tree_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
100                                                                 GtkTreeViewColumn       *tree_column);
101
102 /* Internal functions */
103 static void gtk_tree_view_column_sort                          (GtkTreeViewColumn       *tree_column,
104                                                                 gpointer                 data);
105 static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn       *tree_column);
106 static void gtk_tree_view_column_set_attributesv               (GtkTreeViewColumn       *tree_column,
107                                                                 GtkCellRenderer         *cell_renderer,
108                                                                 va_list                  args);
109 static GtkTreeViewColumnCellInfo *gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
110                                                                       GtkCellRenderer   *cell_renderer);
111
112
113
114 static GtkObjectClass *parent_class = NULL;
115 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
116
117
118 GtkType
119 gtk_tree_view_column_get_type (void)
120 {
121   static GtkType tree_column_type = 0;
122
123   if (!tree_column_type)
124     {
125       static const GTypeInfo tree_column_info =
126       {
127         sizeof (GtkTreeViewColumnClass),
128         NULL,           /* base_init */
129         NULL,           /* base_finalize */
130         (GClassInitFunc) gtk_tree_view_column_class_init,
131         NULL,           /* class_finalize */
132         NULL,           /* class_data */
133         sizeof (GtkTreeViewColumn),
134         0,
135         (GInstanceInitFunc) gtk_tree_view_column_init,
136       };
137
138       tree_column_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn", &tree_column_info, 0);
139     }
140
141   return tree_column_type;
142 }
143
144 static void
145 gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
146 {
147   GObjectClass *object_class;
148
149   object_class = (GObjectClass*) class;
150
151   parent_class = g_type_class_peek_parent (class);
152
153   class->clicked = NULL;
154
155   object_class->finalize = gtk_tree_view_column_finalize;
156   object_class->set_property = gtk_tree_view_column_set_property;
157   object_class->get_property = gtk_tree_view_column_get_property;
158   
159   tree_column_signals[CLICKED] =
160     g_signal_new ("clicked",
161                   GTK_CLASS_TYPE (object_class),
162                   G_SIGNAL_RUN_LAST,
163                   G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
164                   NULL, NULL,
165                   _gtk_marshal_VOID__VOID,
166                   GTK_TYPE_NONE, 0);
167
168   g_object_class_install_property (object_class,
169                                    PROP_VISIBLE,
170                                    g_param_spec_boolean ("visible",
171                                                         _("Visible"),
172                                                         _("Whether to display the column"),
173                                                          TRUE,
174                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
175   
176   g_object_class_install_property (object_class,
177                                    PROP_RESIZABLE,
178                                    g_param_spec_boolean ("resizable",
179                                                          _("Resizable"),
180                                                          _("Column is user-resizable"),
181                                                          FALSE,
182                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
183   
184   g_object_class_install_property (object_class,
185                                    PROP_WIDTH,
186                                    g_param_spec_int ("width",
187                                                      _("Width"),
188                                                      _("Current width of the column"),
189                                                      0,
190                                                      G_MAXINT,
191                                                      0,
192                                                      G_PARAM_READABLE));
193   g_object_class_install_property (object_class,
194                                    PROP_SIZING,
195                                    g_param_spec_enum ("sizing",
196                                                       _("Sizing"),
197                                                       _("Resize mode of the column"),
198                                                       GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
199                                                       GTK_TREE_VIEW_COLUMN_AUTOSIZE,
200                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
201   
202   g_object_class_install_property (object_class,
203                                    PROP_FIXED_WIDTH,
204                                    g_param_spec_int ("fixed_width",
205                                                      _("Fixed Width"),
206                                                      _("Current fixed width of the column"),
207                                                      1,
208                                                      G_MAXINT,
209                                                      1, /* not useful */
210                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
211
212   g_object_class_install_property (object_class,
213                                    PROP_MIN_WIDTH,
214                                    g_param_spec_int ("min_width",
215                                                      _("Minimum Width"),
216                                                      _("Minimum allowed width of the column"),
217                                                      -1,
218                                                      G_MAXINT,
219                                                      -1,
220                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
221
222   g_object_class_install_property (object_class,
223                                    PROP_MAX_WIDTH,
224                                    g_param_spec_int ("max_width",
225                                                      _("Maximum Width"),
226                                                      _("Maximum allowed width of the column"),
227                                                      -1,
228                                                      G_MAXINT,
229                                                      -1,
230                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
231
232   g_object_class_install_property (object_class,
233                                    PROP_TITLE,
234                                    g_param_spec_string ("title",
235                                                         _("Title"),
236                                                         _("Title to appear in column header"),
237                                                         "",
238                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
239   
240   g_object_class_install_property (object_class,
241                                    PROP_CLICKABLE,
242                                    g_param_spec_boolean ("clickable",
243                                                         _("Clickable"),
244                                                         _("Whether the header can be clicked"),
245                                                          TRUE,
246                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
247   
248
249   g_object_class_install_property (object_class,
250                                    PROP_WIDGET,
251                                    g_param_spec_object ("widget",
252                                                         _("Widget"),
253                                                         _("Widget to put in column header button instead of column title"),
254                                                         GTK_TYPE_WIDGET,
255                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
256
257   g_object_class_install_property (object_class,
258                                    PROP_ALIGNMENT,
259                                    g_param_spec_float ("alignment",
260                                                        _("Alignment"),
261                                                        _("X Alignment of the column header text or widget"),
262                                                        0.0,
263                                                        1.0,
264                                                        0.5,
265                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
266
267   g_object_class_install_property (object_class,
268                                    PROP_REORDERABLE,
269                                    g_param_spec_boolean ("reorderable",
270                                                          _("Reorderable"),
271                                                          _("Whether the column can be reordered around the headers"),
272                                                          FALSE,
273                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
274
275   g_object_class_install_property (object_class,
276                                    PROP_SORT_INDICATOR,
277                                    g_param_spec_boolean ("sort_indicator",
278                                                         _("Sort indicator"),
279                                                         _("Whether to show a sort indicator"),
280                                                          FALSE,
281                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
282
283   g_object_class_install_property (object_class,
284                                    PROP_SORT_ORDER,
285                                    g_param_spec_enum ("sort_order",
286                                                       _("Sort order"),
287                                                       _("Sort direction the sort indicator should indicate"),
288                                                       GTK_TYPE_SORT_TYPE,
289                                                       GTK_SORT_ASCENDING,
290                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
291   
292 }
293
294 static void
295 gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
296 {
297   tree_column->button = NULL;
298   tree_column->xalign = 0.0;
299   tree_column->width = 0;
300   tree_column->requested_width = -1;
301   tree_column->min_width = -1;
302   tree_column->max_width = -1;
303   tree_column->resized_width = 0;
304   tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
305   tree_column->visible = TRUE;
306   tree_column->resizable = FALSE;
307   tree_column->clickable = FALSE;
308   tree_column->dirty = TRUE;
309   tree_column->sort_order = GTK_SORT_ASCENDING;
310   tree_column->show_sort_indicator = FALSE;
311   tree_column->property_changed_signal = 0;
312   tree_column->sort_clicked_signal = 0;
313   tree_column->sort_column_changed_signal = 0;
314   tree_column->sort_column_id = -1;
315   tree_column->reorderable = FALSE;
316   tree_column->maybe_reordered = FALSE;
317   tree_column->use_resized_width = FALSE;
318 }
319
320 static void
321 gtk_tree_view_column_finalize (GObject *object)
322 {
323   GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
324   GList *list;
325
326   for (list = tree_column->cell_list; list; list = list->next)
327     {
328       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
329       if (info->func_data && info->destroy)
330         (info->destroy) (info->func_data);
331       gtk_tree_view_column_clear_attributes (tree_column, info->cell);
332       g_object_unref (G_OBJECT (info->cell));
333       g_free (info);
334     }
335
336   g_free (tree_column->title);
337
338   G_OBJECT_CLASS (parent_class)->finalize (object);
339 }
340
341 static void
342 gtk_tree_view_column_set_property (GObject         *object,
343                                    guint            prop_id,
344                                    const GValue    *value,
345                                    GParamSpec      *pspec)
346 {
347   GtkTreeViewColumn *tree_column;
348
349   tree_column = GTK_TREE_VIEW_COLUMN (object);
350
351   switch (prop_id)
352     {
353     case PROP_VISIBLE:
354       gtk_tree_view_column_set_visible (tree_column,
355                                         g_value_get_boolean (value));
356       break;
357
358     case PROP_RESIZABLE:
359       gtk_tree_view_column_set_resizable (tree_column,
360                                           g_value_get_boolean (value));
361       break;
362
363     case PROP_SIZING:
364       gtk_tree_view_column_set_sizing (tree_column,
365                                        g_value_get_enum (value));
366       break;
367
368     case PROP_FIXED_WIDTH:
369       gtk_tree_view_column_set_fixed_width (tree_column,
370                                             g_value_get_int (value));
371       break;
372
373     case PROP_MIN_WIDTH:
374       gtk_tree_view_column_set_min_width (tree_column,
375                                           g_value_get_int (value));
376       break;
377
378     case PROP_MAX_WIDTH:
379       gtk_tree_view_column_set_max_width (tree_column,
380                                           g_value_get_int (value));
381       break;
382
383     case PROP_TITLE:
384       gtk_tree_view_column_set_title (tree_column,
385                                       g_value_get_string (value));
386       break;
387
388     case PROP_CLICKABLE:
389       gtk_tree_view_column_set_clickable (tree_column,
390                                           g_value_get_boolean (value));
391       break;
392
393     case PROP_WIDGET:
394       gtk_tree_view_column_set_widget (tree_column,
395                                        (GtkWidget*) g_value_get_object (value));
396       break;
397
398     case PROP_ALIGNMENT:
399       gtk_tree_view_column_set_alignment (tree_column,
400                                           g_value_get_float (value));
401       break;
402
403     case PROP_REORDERABLE:
404       gtk_tree_view_column_set_reorderable (tree_column,
405                                             g_value_get_boolean (value));
406       break;
407
408     case PROP_SORT_INDICATOR:
409       gtk_tree_view_column_set_sort_indicator (tree_column,
410                                                g_value_get_boolean (value));
411       break;
412
413     case PROP_SORT_ORDER:
414       gtk_tree_view_column_set_sort_order (tree_column,
415                                            g_value_get_enum (value));
416       break;
417       
418     default:
419       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
420       break;
421     }
422 }
423
424 static void
425 gtk_tree_view_column_get_property (GObject         *object,
426                                    guint            prop_id,
427                                    GValue          *value,
428                                    GParamSpec      *pspec)
429 {
430   GtkTreeViewColumn *tree_column;
431
432   tree_column = GTK_TREE_VIEW_COLUMN (object);
433
434   switch (prop_id)
435     {
436     case PROP_VISIBLE:
437       g_value_set_boolean (value,
438                            gtk_tree_view_column_get_visible (tree_column));
439       break;
440
441     case PROP_RESIZABLE:
442       g_value_set_boolean (value,
443                            gtk_tree_view_column_get_resizable (tree_column));
444       break;
445
446     case PROP_WIDTH:
447       g_value_set_int (value,
448                        gtk_tree_view_column_get_width (tree_column));
449       break;
450
451     case PROP_SIZING:
452       g_value_set_enum (value,
453                         gtk_tree_view_column_get_sizing (tree_column));
454       break;
455
456     case PROP_FIXED_WIDTH:
457       g_value_set_int (value,
458                        gtk_tree_view_column_get_fixed_width (tree_column));
459       break;
460
461     case PROP_MIN_WIDTH:
462       g_value_set_int (value,
463                        gtk_tree_view_column_get_min_width (tree_column));
464       break;
465
466     case PROP_MAX_WIDTH:
467       g_value_set_int (value,
468                        gtk_tree_view_column_get_max_width (tree_column));
469       break;
470
471     case PROP_TITLE:
472       g_value_set_string (value,
473                           gtk_tree_view_column_get_title (tree_column));
474       break;
475
476     case PROP_CLICKABLE:
477       g_value_set_boolean (value,
478                            gtk_tree_view_column_get_clickable (tree_column));
479       break;
480
481     case PROP_WIDGET:
482       g_value_set_object (value,
483                           (GObject*) gtk_tree_view_column_get_widget (tree_column));
484       break;
485
486     case PROP_ALIGNMENT:
487       g_value_set_float (value,
488                          gtk_tree_view_column_get_alignment (tree_column));
489       break;
490
491     case PROP_REORDERABLE:
492       g_value_set_boolean (value,
493                            gtk_tree_view_column_get_reorderable (tree_column));
494       break;
495
496     case PROP_SORT_INDICATOR:
497       g_value_set_boolean (value,
498                            gtk_tree_view_column_get_sort_indicator (tree_column));
499       break;
500
501     case PROP_SORT_ORDER:
502       g_value_set_enum (value,
503                         gtk_tree_view_column_get_sort_order (tree_column));
504       break;
505       
506     default:
507       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
508       break;
509     }
510 }
511
512 /* Helper functions
513  */
514
515 /* Button handling code
516  */
517 static void
518 gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
519 {
520   GtkTreeView *tree_view;
521   GtkWidget *child;
522   GtkWidget *hbox;
523
524   tree_view = (GtkTreeView *) tree_column->tree_view;
525
526   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
527   g_return_if_fail (tree_column->button == NULL);
528
529   gtk_widget_push_composite_child ();
530   tree_column->button = gtk_button_new ();
531   gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
532   gtk_widget_pop_composite_child ();
533
534   /* make sure we own a reference to it as well. */
535   if (tree_view->priv->header_window)
536     gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
537   gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
538   
539   gtk_signal_connect (GTK_OBJECT (tree_column->button), "event",
540                       (GtkSignalFunc) gtk_tree_view_column_button_event,
541                       (gpointer) tree_column);
542   
543   gtk_signal_connect (GTK_OBJECT (tree_column->button), "clicked",
544                       (GtkSignalFunc) gtk_tree_view_column_button_clicked,
545                       (gpointer) tree_column);
546
547   tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
548
549   hbox = gtk_hbox_new (FALSE, 2);
550   tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
551
552   if (tree_column->child)
553     child = tree_column->child;
554   else
555     {
556       child = gtk_label_new (tree_column->title);
557       gtk_widget_show (child);
558     }
559
560   if (tree_column->xalign <= 0.5)
561     gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
562   else
563     gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
564
565   gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
566         
567   gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
568   gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
569
570   gtk_widget_show (hbox);
571   gtk_widget_show (tree_column->alignment);
572   gtk_tree_view_column_update_button (tree_column);
573 }
574
575 static void 
576 gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
577 {
578   GtkWidget *hbox;
579   GtkWidget *alignment;
580   GtkWidget *arrow;
581   GtkWidget *current_child;
582
583   /* Create a button if necessary */
584   if (tree_column->visible &&
585       tree_column->button == NULL &&
586       tree_column->tree_view &&
587       GTK_WIDGET_REALIZED (tree_column->tree_view))
588     gtk_tree_view_column_create_button (tree_column);
589   
590   if (! tree_column->button)
591     return;
592
593   hbox = GTK_BIN (tree_column->button)->child;
594   alignment = tree_column->alignment;
595   arrow = tree_column->arrow;
596   current_child = GTK_BIN (alignment)->child;
597
598   /* Set up the actual button */
599   gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
600                      0.5, 0.0, 0.0);
601       
602   if (tree_column->child)
603     {
604       if (current_child != tree_column->child)
605         {
606           gtk_container_remove (GTK_CONTAINER (alignment),
607                                 current_child);
608           gtk_container_add (GTK_CONTAINER (alignment),
609                              tree_column->child);
610         }
611     }
612   else 
613     {
614       if (current_child == NULL)
615         {
616           current_child = gtk_label_new (NULL);
617           gtk_widget_show (current_child);
618           gtk_container_add (GTK_CONTAINER (alignment),
619                              current_child);
620         }
621
622       g_return_if_fail (GTK_IS_LABEL (current_child));
623
624       if (tree_column->title)
625         gtk_label_set_text (GTK_LABEL (current_child),
626                             tree_column->title);
627       else
628         gtk_label_set_text (GTK_LABEL (current_child),
629                             "");
630     }
631
632   switch (tree_column->sort_order)
633     {
634     case GTK_SORT_ASCENDING:
635       gtk_arrow_set (GTK_ARROW (arrow),
636                      GTK_ARROW_DOWN,
637                      GTK_SHADOW_IN);
638       break;
639
640     case GTK_SORT_DESCENDING:
641       gtk_arrow_set (GTK_ARROW (arrow),
642                      GTK_ARROW_UP,
643                      GTK_SHADOW_IN);
644       break;
645           
646     default:
647       g_warning (G_STRLOC": bad sort order");
648       break;
649     }
650
651   /* Put arrow on the right if the text is left-or-center justified,
652        * and on the left otherwise; do this by packing boxes, so flipping
653        * text direction will reverse things
654        */
655   gtk_widget_ref (arrow);
656   gtk_container_remove (GTK_CONTAINER (hbox), arrow);
657
658   if (tree_column->xalign <= 0.5)
659     {
660       gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
661     }
662   else
663     {
664       gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
665       /* move it to the front */
666       gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
667     }
668   gtk_widget_unref (arrow);
669
670   if (tree_column->show_sort_indicator)
671     gtk_widget_show (arrow);
672   else
673     gtk_widget_hide (arrow);
674
675   /* It's always safe to hide the button.  It isn't always safe to show it, as if you show it
676    * before it's realized, it'll get the wrong window. */
677   if (tree_column->button &&
678       tree_column->tree_view != NULL &&
679       GTK_WIDGET_REALIZED (tree_column->tree_view))
680     {
681       if (tree_column->visible)
682         {
683           gtk_widget_show_now (tree_column->button);
684           if (tree_column->window)
685             {
686               if (tree_column->resizable)
687                 {
688                   gdk_window_show (tree_column->window);
689                   gdk_window_raise (tree_column->window);
690                 }
691               else
692                 {
693                   gdk_window_hide (tree_column->window);
694                 }
695             }
696         }
697       else
698         {
699           gtk_widget_hide (tree_column->button);
700           if (tree_column->window)
701             gdk_window_hide (tree_column->window);
702         }
703     }
704   
705   if (tree_column->reorderable || tree_column->clickable)
706     {
707       GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
708     }
709   else
710     {
711       GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
712       if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
713         {
714           GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
715           if (GTK_WIDGET_TOPLEVEL (toplevel))
716             {
717               gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
718             }
719         }
720     }
721   /* Queue a resize on the assumption that we always want to catch all changes
722    * and columns don't change all that often.
723    */
724   if (GTK_WIDGET_REALIZED (tree_column->tree_view))
725      gtk_widget_queue_resize (tree_column->tree_view);
726
727 }
728
729 /* Button signal handlers
730  */
731
732 static gint
733 gtk_tree_view_column_button_event (GtkWidget *widget,
734                                    GdkEvent  *event,
735                                    gpointer   data)
736 {
737   GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
738
739   g_return_val_if_fail (event != NULL, FALSE);
740
741   if (event->type == GDK_BUTTON_PRESS &&
742       column->reorderable)
743     {
744       column->maybe_reordered = TRUE;
745       gdk_window_get_pointer (widget->window,
746                               &column->drag_x,
747                               &column->drag_y,
748                               NULL);
749       gtk_widget_grab_focus (widget);
750     }
751
752   if (event->type == GDK_BUTTON_RELEASE &&
753       column->maybe_reordered)
754     column->maybe_reordered = FALSE;
755
756   if (event->type == GDK_MOTION_NOTIFY &&
757       (column->maybe_reordered) &&
758       (gtk_drag_check_threshold (widget,
759                                  column->drag_x,
760                                  column->drag_y,
761                                  (gint) ((GdkEventMotion *)event)->x,
762                                  (gint) ((GdkEventMotion *)event)->y)))
763     {
764       column->maybe_reordered = FALSE;
765       /* this is to change our drag_x to be relative to
766        * tree_view->priv->bin_window, instead of our window.
767        */
768       column->drag_x -= column->button->allocation.x;
769       _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
770       return TRUE;
771     }
772   if (column->clickable == FALSE)
773     {
774       switch (event->type)
775         {
776         case GDK_BUTTON_PRESS:
777         case GDK_2BUTTON_PRESS:
778         case GDK_3BUTTON_PRESS:
779         case GDK_MOTION_NOTIFY:
780         case GDK_BUTTON_RELEASE:
781         case GDK_ENTER_NOTIFY:
782         case GDK_LEAVE_NOTIFY:
783           return TRUE;
784         default:
785           return FALSE;
786         }
787     }
788   return FALSE;
789 }
790
791
792 static void
793 gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
794 {
795   g_signal_emit_by_name (G_OBJECT (data), "clicked");
796 }
797
798 static void
799 gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
800                                          GtkTreeViewColumn *column)
801 {
802   gint sort_column_id;
803   GtkSortType order;
804
805   if (gtk_tree_sortable_get_sort_column_id (sortable,
806                                             &sort_column_id,
807                                             &order))
808     {
809       if (sort_column_id == column->sort_column_id)
810         {
811           gtk_tree_view_column_set_sort_indicator (column, TRUE);
812           gtk_tree_view_column_set_sort_order (column, order);
813         }
814       else
815         {
816           gtk_tree_view_column_set_sort_indicator (column, FALSE);
817         }
818     }
819   else
820     {
821       gtk_tree_view_column_set_sort_indicator (column, FALSE);
822     }
823 }
824
825 static void
826 gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
827                            gpointer           data)
828 {
829   gint sort_column_id;
830   GtkSortType order;
831   gboolean has_sort_column;
832   gboolean has_default_sort_func;
833
834   g_return_if_fail (tree_column->tree_view != NULL);
835
836   has_sort_column =
837     gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
838                                           &sort_column_id,
839                                           &order);
840   has_default_sort_func =
841     gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model));
842
843   if (has_sort_column &&
844       sort_column_id == tree_column->sort_column_id)
845     {
846       if (order == GTK_SORT_ASCENDING)
847         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
848                                               tree_column->sort_column_id,
849                                               GTK_SORT_DESCENDING);
850       else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
851         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
852                                               GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
853                                               GTK_SORT_ASCENDING);
854       else
855         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
856                                               tree_column->sort_column_id,
857                                               GTK_SORT_ASCENDING);
858     }
859   else
860     {
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 }
866
867
868 static void
869 gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
870 {
871   GtkTreeModel *model;
872
873   if (tree_column->tree_view == NULL)
874     return;
875
876   model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
877
878   if (model == NULL)
879     return;
880
881   if (GTK_IS_TREE_SORTABLE (model) &&
882       tree_column->sort_column_id != -1)
883     {
884       gint real_sort_column_id;
885       GtkSortType real_order;
886
887       if (tree_column->sort_column_changed_signal == 0)
888         tree_column->sort_column_changed_signal =
889           g_signal_connect (G_OBJECT (model), "sort_column_changed",
890                             GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed),
891                             tree_column);
892       
893       if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
894                                                 &real_sort_column_id,
895                                                 &real_order) &&
896           (real_sort_column_id == tree_column->sort_column_id))
897         {
898           gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
899           gtk_tree_view_column_set_sort_order (tree_column, real_order);
900
901           return;
902         }
903     }
904 }
905
906
907 /* Exported Private Functions.
908  * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
909  */
910
911 void
912 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
913 {
914   GtkTreeView *tree_view;
915   GdkWindowAttr attr;
916   guint attributes_mask;
917
918   tree_view = (GtkTreeView *)column->tree_view;
919
920   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
921   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
922   g_return_if_fail (tree_view->priv->header_window != NULL);
923   g_return_if_fail (column->button != NULL);
924
925   gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
926
927   if (column->visible)
928     gtk_widget_show (column->button);
929
930   attr.window_type = GDK_WINDOW_CHILD;
931   attr.wclass = GDK_INPUT_ONLY;
932   attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
933   attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
934   attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
935   attr.event_mask = (GDK_BUTTON_PRESS_MASK |
936                      GDK_BUTTON_RELEASE_MASK |
937                      GDK_POINTER_MOTION_MASK |
938                      GDK_POINTER_MOTION_HINT_MASK |
939                      GDK_KEY_PRESS_MASK);
940   attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
941   attr.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
942
943   attr.y = 0;
944   attr.width = TREE_VIEW_DRAG_WIDTH;
945   attr.height = tree_view->priv->header_height;
946
947   attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
948           
949   column->window = gdk_window_new (tree_view->priv->header_window,
950                                    &attr, attributes_mask);
951   gdk_window_set_user_data (column->window, tree_view);
952
953   gtk_tree_view_column_update_button (column);
954
955   gdk_cursor_unref (attr.cursor);
956 }
957
958 void
959 _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
960 {
961   g_return_if_fail (column != NULL);
962   g_return_if_fail (column->window != NULL);
963
964   gdk_window_set_user_data (column->window, NULL);
965   gdk_window_destroy (column->window);
966   column->window = NULL;
967 }
968
969 void
970 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
971                                      GtkTreeView       *tree_view)
972 {
973   g_assert (column->tree_view == NULL);
974
975   column->tree_view = GTK_WIDGET (tree_view);
976   gtk_tree_view_column_create_button (column);
977
978   column->property_changed_signal =
979           g_signal_connect_swapped (GTK_OBJECT (tree_view),
980                                     "notify::model",
981                                     GTK_SIGNAL_FUNC (gtk_tree_view_column_setup_sort_column_id_callback),
982                                     column);
983
984   gtk_tree_view_column_setup_sort_column_id_callback (column);
985 }
986
987 void
988 _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
989 {
990   if (column->tree_view && column->button)
991     {
992       gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
993     }
994   if (column->property_changed_signal)
995     {
996       g_signal_handler_disconnect (G_OBJECT (column->tree_view), column->property_changed_signal);
997       column->property_changed_signal = 0;
998     }
999
1000   if (column->sort_column_changed_signal)
1001     {
1002       g_signal_handler_disconnect (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view))),
1003                                    column->sort_column_changed_signal);
1004       column->sort_column_changed_signal = 0;
1005     }
1006
1007   column->tree_view = NULL;
1008   column->button = NULL;
1009 }
1010
1011 /* Public Functions */
1012
1013
1014 /**
1015  * gtk_tree_view_column_new:
1016  * 
1017  * Creates a new #GtkTreeViewColumn.
1018  * 
1019  * Return value: A newly created #GtkTreeViewColumn.
1020  **/
1021 GtkTreeViewColumn *
1022 gtk_tree_view_column_new (void)
1023 {
1024   GtkTreeViewColumn *tree_column;
1025
1026   tree_column = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
1027
1028   return tree_column;
1029 }
1030
1031 /**
1032  * gtk_tree_view_column_new_with_attributes:
1033  * @title: The title to set the header to.
1034  * @cell: The #GtkCellRenderer.
1035  * @Varargs: A %NULL-terminated list of attributes.
1036  * 
1037  * Creates a new #GtkTreeViewColumn with a number of default values.  This is
1038  * equivalent to calling gtk_tree_view_column_set_title(),
1039  * gtk_tree_view_column_pack_start(), and
1040  * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
1041  * 
1042  * Return value: A newly created #GtkTreeViewColumn.
1043  **/
1044 GtkTreeViewColumn *
1045 gtk_tree_view_column_new_with_attributes (const gchar     *title,
1046                                           GtkCellRenderer *cell,
1047                                           ...)
1048 {
1049   GtkTreeViewColumn *retval;
1050   va_list args;
1051
1052   retval = gtk_tree_view_column_new ();
1053
1054   gtk_tree_view_column_set_title (retval, title);
1055   gtk_tree_view_column_pack_start (retval, cell, TRUE);
1056
1057   va_start (args, cell);
1058   gtk_tree_view_column_set_attributesv (retval, cell, args);
1059   va_end (args);
1060
1061   return retval;
1062 }
1063
1064 static GtkTreeViewColumnCellInfo *
1065 gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
1066                                     GtkCellRenderer   *cell_renderer)
1067 {
1068   GList *list;
1069   for (list = tree_column->cell_list; list; list = list->next)
1070     if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer)
1071       return (GtkTreeViewColumnCellInfo *) list->data;
1072   return NULL;
1073 }
1074
1075
1076 /**
1077  * gtk_tree_view_column_pack_start:
1078  * @tree_column: A #GtkTreeViewColumn.
1079  * @cell: The #GtkCellRenderer. 
1080  * @expand: %TRUE if @cell is to be given extra space allocated to box.
1081  * 
1082  **/
1083 void
1084 gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
1085                                  GtkCellRenderer   *cell,
1086                                  gboolean           expand)
1087 {
1088   GtkTreeViewColumnCellInfo *cell_info;
1089
1090   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1091   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1092   g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1093
1094   g_object_ref (G_OBJECT (cell));
1095   gtk_object_sink (GTK_OBJECT (cell));
1096
1097   cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1098   cell_info->cell = cell;
1099   cell_info->expand = expand ? TRUE : FALSE;
1100   cell_info->pack = GTK_PACK_START;
1101   cell_info->has_focus = 0;
1102   cell_info->attributes = NULL;
1103
1104   tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1105 }
1106
1107 void
1108 gtk_tree_view_column_pack_end (GtkTreeViewColumn  *tree_column,
1109                                GtkCellRenderer    *cell,
1110                                gboolean            expand)
1111 {
1112   GtkTreeViewColumnCellInfo *cell_info;
1113
1114   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1115   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1116   g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1117
1118   g_object_ref (G_OBJECT (cell));
1119   gtk_object_sink (GTK_OBJECT (cell));
1120
1121   cell_info = g_new (GtkTreeViewColumnCellInfo, 1);
1122   cell_info->cell = cell;
1123   cell_info->expand = expand ? TRUE : FALSE;
1124   cell_info->pack = GTK_PACK_END;
1125   cell_info->has_focus = 0;
1126   cell_info->attributes = NULL;
1127
1128   tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1129 }
1130
1131
1132 /**
1133  * gtk_tree_view_column_clear:
1134  * @tree_column: A #GtkTreeViewColumn
1135  * 
1136  * Unsets all the mappings on all renderers on the @tree_column.
1137  **/
1138 void
1139 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1140 {
1141   GList *list;
1142   g_return_if_fail (tree_column != NULL);
1143
1144   for (list = tree_column->cell_list; list; list = list->next)
1145     {
1146       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1147
1148       g_object_unref (G_OBJECT (info->cell));
1149       gtk_tree_view_column_clear_attributes (tree_column, info->cell);
1150       g_free (info);
1151     }
1152
1153   g_list_free (tree_column->cell_list);
1154   tree_column->cell_list = NULL;
1155 }
1156
1157 /**
1158  * gtk_tree_view_column_get_cell_renderers:
1159  * @tree_column: A #GtkTreeViewColumn
1160  * 
1161  * Returns a newly-allocated #GList of all the cell renderers in the column, 
1162  * in no particular order.  The list must be freed with g_list_free().
1163  * 
1164  * Return value: A list of #GtkCellRenderers
1165  **/
1166 GList *
1167 gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
1168 {
1169   GList *retval = NULL, *list;
1170
1171   g_return_val_if_fail (tree_column != NULL, NULL);
1172
1173   for (list = tree_column->cell_list; list; list = list->next)
1174     {
1175       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1176
1177       retval = g_list_append (retval, info->cell);
1178     }
1179
1180   return retval;
1181 }
1182
1183 /**
1184  * gtk_tree_view_column_add_attribute:
1185  * @tree_column: A #GtkTreeViewColumn.
1186  * @cell_renderer: the #GtkCellRenderer to set attributes on
1187  * @attribute: An attribute on the renderer
1188  * @column: The column position on the model to get the attribute from.
1189  * 
1190  * Adds an attribute mapping to the list in @tree_column.  The @column is the
1191  * column of the model to get a value from, and the @attribute is the
1192  * parameter on @cell_renderer to be set from the value. So for example
1193  * if column 2 of the model contains strings, you could have the
1194  * "text" attribute of a #GtkCellRendererText get its values from
1195  * column 2.
1196  **/
1197 void
1198 gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1199                                     GtkCellRenderer   *cell_renderer,
1200                                     const gchar       *attribute,
1201                                     gint               column)
1202 {
1203   GtkTreeViewColumnCellInfo *info;
1204
1205   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1206   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1207   g_return_if_fail (info != NULL);
1208
1209   info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
1210   info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
1211
1212   if (tree_column->tree_view)
1213     gtk_tree_view_column_cell_set_dirty (tree_column);
1214
1215 }
1216
1217 static void
1218 gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
1219                                       GtkCellRenderer   *cell_renderer,
1220                                       va_list            args)
1221 {
1222   gchar *attribute;
1223   gint column;
1224
1225   attribute = va_arg (args, gchar *);
1226
1227   gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1228   
1229   while (attribute != NULL)
1230     {
1231       column = va_arg (args, gint);
1232       gtk_tree_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1233       attribute = va_arg (args, gchar *);
1234     }
1235 }
1236
1237 /**
1238  * gtk_tree_view_column_set_attributes:
1239  * @tree_column: A #GtkTreeViewColumn.
1240  * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1241  * @Varargs: A %NULL-terminated list of attributes.
1242  * 
1243  * Sets the attributes in the list as the attributes of @tree_column.
1244  * The attributes should be in attribute/column order, as in
1245  * gtk_tree_view_column_add_attribute(). All existing attributes
1246  * are removed, and replaced with the new attributes.
1247  **/
1248 void
1249 gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column,
1250                                      GtkCellRenderer   *cell_renderer,
1251                                      ...)
1252 {
1253   va_list args;
1254
1255   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1256   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1257   g_return_if_fail (gtk_tree_view_column_get_cell_info (tree_column, cell_renderer));
1258
1259   va_start (args, cell_renderer);
1260   gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args);
1261   va_end (args);
1262 }
1263
1264
1265 /**
1266  * gtk_tree_view_column_set_cell_data_func:
1267  * @tree_column: A #GtkTreeViewColumn
1268  * @cell_renderer: A #GtkCellRenderer
1269  * @func: The #GtkTreeViewColumnFunc to use. 
1270  * @func_data: The user data for @func.
1271  * @destroy: The destroy notification for @func_data
1272  * 
1273  * Sets the #GtkTreeViewColumnFunc to use for the column.  This
1274  * function is used instead of the standard attributes mapping for
1275  * setting the column value, and should set the value of @tree_column's
1276  * cell renderer as appropriate.  @func may be %NULL to remove an
1277  * older one.
1278  **/
1279 void
1280 gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn   *tree_column,
1281                                          GtkCellRenderer     *cell_renderer,
1282                                          GtkTreeCellDataFunc  func,
1283                                          gpointer             func_data,
1284                                          GtkDestroyNotify     destroy)
1285 {
1286   GtkTreeViewColumnCellInfo *info;
1287
1288   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1289   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1290   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1291
1292   g_return_if_fail (info != NULL);
1293
1294   if (func == info->func &&
1295       func_data == info->func_data &&
1296       destroy == info->destroy)
1297     return;
1298
1299   if (info->func_data && info->destroy)
1300     (info->destroy) (info->func_data);
1301
1302   info->func = func;
1303   info->func_data = func_data;
1304   info->destroy = destroy;
1305
1306   if (tree_column->tree_view)
1307     gtk_tree_view_column_cell_set_dirty (tree_column);
1308 }
1309
1310
1311 /**
1312  * gtk_tree_view_column_clear_attributes:
1313  * @tree_column: a #GtkTreeViewColumn
1314  * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1315  * 
1316  * Clears all existing attributes previously set with
1317  * gtk_tree_view_column_set_attributes().
1318  **/
1319 void
1320 gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
1321                                        GtkCellRenderer   *cell_renderer)
1322 {
1323   GtkTreeViewColumnCellInfo *info;
1324   GSList *list;
1325
1326   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1327   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1328   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1329
1330   list = info->attributes;
1331
1332   while (list && list->next)
1333     {
1334       g_free (list->data);
1335       list = list->next->next;
1336     }
1337   g_slist_free (info->attributes);
1338   info->attributes = NULL;
1339
1340   if (tree_column->tree_view)
1341     gtk_tree_view_column_cell_set_dirty (tree_column);
1342 }
1343
1344
1345 /**
1346  * gtk_tree_view_column_set_spacing:
1347  * @tree_column: A #GtkTreeViewColumn.
1348  * @spacing: distance between cell renderers in pixels.
1349  * 
1350  * Sets the spacing field of @tree_column, which is the number of pixels to
1351  * place between cell renderers packed into it.
1352  **/
1353 void
1354 gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
1355                                   gint               spacing)
1356 {
1357   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1358   g_return_if_fail (spacing >= 0);
1359
1360   if (tree_column->spacing == spacing)
1361     return;
1362
1363   tree_column->spacing = spacing;
1364   if (tree_column->tree_view)
1365     gtk_tree_view_column_cell_set_dirty (tree_column);
1366 }
1367
1368 /**
1369  * gtk_tree_view_column_get_spacing:
1370  * @tree_column: A #GtkTreeViewColumn.
1371  * 
1372  * Returns the spacing of @tree_column.
1373  * 
1374  * Return value: the spacing of @tree_column.
1375  **/
1376 gint
1377 gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column)
1378 {
1379   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1380
1381   return tree_column->spacing;
1382 }
1383
1384 /* Options for manipulating the columns */
1385
1386 /**
1387  * gtk_tree_view_column_set_visible:
1388  * @tree_column: A #GtkTreeViewColumn.
1389  * @visible: %TRUE if the @tree_column is visible.
1390  * 
1391  * Sets the visibility of @tree_column.
1392  **/
1393 void
1394 gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
1395                                   gboolean           visible)
1396 {
1397   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1398
1399   visible = !! visible;
1400   
1401   if (tree_column->visible == visible)
1402     return;
1403
1404   tree_column->visible = visible;
1405
1406   gtk_tree_view_column_update_button (tree_column);
1407   g_object_notify (G_OBJECT (tree_column), "visible");
1408 }
1409
1410 /**
1411  * gtk_tree_view_column_get_visible:
1412  * @tree_column: A #GtkTreeViewColumn.
1413  * 
1414  * Returns %TRUE if @tree_column is visible.
1415  * 
1416  * Return value: whether the column is visible or not.  If it is visible, then
1417  * the tree will show the column.
1418  **/
1419 gboolean
1420 gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
1421 {
1422   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1423
1424   return tree_column->visible;
1425 }
1426
1427 void
1428 gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
1429                                     gboolean           resizable)
1430 {
1431   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1432
1433   resizable = !! resizable;
1434
1435   if (tree_column->resizable == resizable)
1436     return;
1437
1438   tree_column->resizable = resizable;
1439
1440   if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1441     gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1442
1443   gtk_tree_view_column_update_button (tree_column);
1444
1445   g_object_notify (G_OBJECT (tree_column), "resizable");
1446 }
1447
1448 gboolean
1449 gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column)
1450 {
1451   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1452
1453   return tree_column->resizable;
1454 }
1455
1456
1457 /**
1458  * gtk_tree_view_column_set_sizing:
1459  * @tree_column: A #GtkTreeViewColumn.
1460  * @type: The #GtkTreeViewColumnSizing.
1461  * 
1462  * Sets the growth behavior of @tree_column to @type.
1463  **/
1464 void
1465 gtk_tree_view_column_set_sizing (GtkTreeViewColumn       *tree_column,
1466                                  GtkTreeViewColumnSizing  type)
1467 {
1468   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1469
1470   if (type == tree_column->column_type)
1471     return;
1472
1473   if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1474     gtk_tree_view_column_set_resizable (tree_column, FALSE);
1475
1476 #if 0
1477   /* I was clearly on crack when I wrote this.  I'm not sure what's supposed to
1478    * be below so I'll leave it until I figure it out.
1479    */
1480   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE &&
1481       tree_column->requested_width != -1)
1482     {
1483       gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width);
1484     }
1485 #endif
1486   tree_column->column_type = type;
1487
1488   gtk_tree_view_column_update_button (tree_column);
1489
1490   g_object_notify (G_OBJECT (tree_column), "sizing");
1491 }
1492
1493 /**
1494  * gtk_tree_view_column_get_sizing:
1495  * @tree_column: A #GtkTreeViewColumn.
1496  * 
1497  * Returns the current type of @tree_column.
1498  * 
1499  * Return value: The type of @tree_column.
1500  **/
1501 GtkTreeViewColumnSizing
1502 gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column)
1503 {
1504   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1505
1506   return tree_column->column_type;
1507 }
1508
1509 /**
1510  * gtk_tree_view_column_get_width:
1511  * @tree_column: A #GtkTreeViewColumn.
1512  * 
1513  * Returns the current size of @tree_column in pixels.
1514  * 
1515  * Return value: The current width of @tree_column.
1516  **/
1517 gint
1518 gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column)
1519 {
1520   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1521
1522   return tree_column->width;
1523 }
1524
1525 /**
1526  * gtk_tree_view_column_set_fixed_width:
1527  * @tree_column: A #GtkTreeViewColumn.
1528  * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1529  * 
1530  * Sets the size of the column in pixels.  This is meaningful only if the sizing
1531  * type is #GTK_TREE_VIEW_COLUMN_FIXED.  In this case, the value is discarded
1532  * as the size of the column is based on the calculated width of the column. The
1533  * width is clamped to the min/max width for the column.
1534  **/
1535 void
1536 gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
1537                                       gint               fixed_width)
1538 {
1539   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1540   g_return_if_fail (fixed_width > 0);
1541
1542   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1543     return;
1544
1545   tree_column->fixed_width = fixed_width;
1546
1547   if (tree_column->tree_view &&
1548       GTK_WIDGET_REALIZED (tree_column->tree_view) &&
1549       tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1550     {
1551       gtk_widget_queue_resize (tree_column->tree_view);
1552     }
1553
1554   g_object_notify (G_OBJECT (tree_column), "fixed_width");
1555 }
1556
1557 /**
1558  * gtk_tree_view_column_get_fixed_width:
1559  * @tree_column: a #GtkTreeViewColumn
1560  * 
1561  * Gets the fixed width of the column.  This value is only meaning may not be
1562  * the actual width of the column on the screen, just what is requested.
1563  * 
1564  * Return value: the fixed width of the column
1565  **/
1566 gint
1567 gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column)
1568 {
1569   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1570
1571   return tree_column->fixed_width;
1572 }
1573
1574 /**
1575  * gtk_tree_view_column_set_min_width:
1576  * @tree_column: A #GtkTreeViewColumn.
1577  * @min_width: The minimum width of the column in pixels, or -1.
1578  * 
1579  * Sets the minimum width of the @tree_column.  If @min_width is -1, then the
1580  * minimum width is unset.
1581  **/
1582 void
1583 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
1584                                     gint               min_width)
1585 {
1586   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1587   g_return_if_fail (min_width >= -1);
1588
1589   if (min_width == tree_column->min_width)
1590     return;
1591
1592   if (tree_column->visible &&
1593       tree_column->tree_view != NULL &&
1594       GTK_WIDGET_REALIZED (tree_column->tree_view))
1595     {
1596       if (min_width > tree_column->width)
1597         gtk_widget_queue_resize (tree_column->tree_view);
1598     }
1599
1600   tree_column->min_width = min_width;
1601   g_object_freeze_notify (G_OBJECT (tree_column));
1602   if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1603     {
1604       tree_column->max_width = min_width;
1605       g_object_notify (G_OBJECT (tree_column), "max_width");
1606     }
1607   g_object_notify (G_OBJECT (tree_column), "min_width");
1608   g_object_thaw_notify (G_OBJECT (tree_column));
1609 }
1610
1611 /**
1612  * gtk_tree_view_column_get_min_width:
1613  * @tree_column: A #GtkTreeViewColumn.
1614  * 
1615  * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1616  * width is set.
1617  * 
1618  * Return value: The minimum width of the @tree_column.
1619  **/
1620 gint
1621 gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
1622 {
1623   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1624
1625   return tree_column->min_width;
1626 }
1627
1628 /**
1629  * gtk_tree_view_column_set_max_width:
1630  * @tree_column: A #GtkTreeViewColumn.
1631  * @max_width: The maximum width of the column in pixels, or -1.
1632  * 
1633  * Sets the maximum width of the @tree_column.  If @max_width is -1, then the
1634  * maximum width is unset.  Note, the column can actually be wider than max
1635  * width if it's the last column in a view.  In this case, the column expands to
1636  * fill any extra space.
1637  **/
1638 void
1639 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
1640                                     gint               max_width)
1641 {
1642   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1643   g_return_if_fail (max_width >= -1);
1644
1645   if (max_width == tree_column->max_width)
1646     return;
1647
1648   if (tree_column->visible &&
1649       tree_column->tree_view != NULL &&
1650       GTK_WIDGET_REALIZED (tree_column->tree_view))
1651     {
1652       if (max_width != -1 && max_width < tree_column->width)
1653         gtk_widget_queue_resize (tree_column->tree_view);
1654     }
1655
1656   tree_column->max_width = max_width;
1657   g_object_freeze_notify (G_OBJECT (tree_column));
1658   if (max_width != -1 && max_width < tree_column->min_width)
1659     {
1660       tree_column->min_width = max_width;
1661       g_object_notify (G_OBJECT (tree_column), "min_width");
1662     }
1663   g_object_notify (G_OBJECT (tree_column), "max_width");
1664   g_object_thaw_notify (G_OBJECT (tree_column));
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   gint focus_line_width;
2135
2136   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2137
2138   if (height)
2139     * height = 0;
2140   if (width)
2141     * width = 0;
2142
2143   gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2144   
2145   for (list = tree_column->cell_list; list; list = list->next)
2146     {
2147       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2148       gboolean visible;
2149       gint new_height = 0;
2150       gint new_width = 0;
2151       g_object_get (info->cell, "visible", &visible, NULL);
2152
2153       if (visible == FALSE)
2154         continue;
2155
2156       if (first_cell == FALSE && *width)
2157         *width += tree_column->spacing;
2158
2159       gtk_cell_renderer_get_size (info->cell,
2160                                   tree_column->tree_view,
2161                                   cell_area,
2162                                   x_offset,
2163                                   y_offset,
2164                                   &new_width,
2165                                   &new_height);
2166
2167       if (height)
2168         * height = MAX (*height, new_height + focus_line_width * 2);
2169       info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2170       if (width)
2171         * width += info->requested_width;
2172       first_cell = TRUE;
2173     }
2174 }
2175
2176 /* both rendering and rendering focus are somewhat complicated, and a bit of
2177  * code.  Rather than duplicate them, we put them together to keep the code in
2178  * one place
2179  */
2180 static void
2181 gtk_tree_view_column_cell_render_or_focus (GtkTreeViewColumn *tree_column,
2182                                            GdkWindow         *window,
2183                                            GdkRectangle      *background_area,
2184                                            GdkRectangle      *cell_area,
2185                                            GdkRectangle      *expose_area,
2186                                            guint              flags,
2187                                            gboolean           render,
2188                                            GdkRectangle      *focus_rectangle)
2189 {
2190   GList *list;
2191   GdkRectangle real_cell_area;
2192   gint expand_cell_count = 0;
2193   gint full_requested_width = 0;
2194   gint extra_space;
2195   gint min_x, min_y, max_x, max_y;
2196   gint focus_line_width;
2197
2198   min_x = G_MAXINT;
2199   min_y = G_MAXINT;
2200   max_x = 0;
2201   max_y = 0;
2202
2203   real_cell_area = *cell_area;
2204
2205   gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2206                         "focus-line-width", &focus_line_width, NULL);
2207   /* Find out how my extra space we have to allocate */
2208   for (list = tree_column->cell_list; list; list = list->next)
2209     {
2210       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2211
2212       if (! info->cell->visible)
2213         continue;
2214
2215       if (info->expand == TRUE)
2216         expand_cell_count ++;
2217       full_requested_width += info->requested_width;
2218     }
2219
2220   extra_space = cell_area->width - full_requested_width;
2221   if (extra_space < 0)
2222     extra_space = 0;
2223
2224   for (list = tree_column->cell_list; list; list = list->next)
2225     {
2226       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2227
2228       if (info->pack == GTK_PACK_END)
2229         continue;
2230
2231       if (! info->cell->visible)
2232         continue;
2233
2234       real_cell_area.width = info->requested_width +
2235         (info->expand?extra_space:0);
2236       real_cell_area.x += focus_line_width;
2237       if (render)
2238         {
2239           gtk_cell_renderer_render (info->cell,
2240                                     window,
2241                                     tree_column->tree_view,
2242                                     background_area,
2243                                     &real_cell_area,
2244                                     expose_area,
2245                                     flags);
2246         }
2247       else
2248         {
2249           gint x_offset, y_offset, width, height;
2250
2251           gtk_cell_renderer_get_size (info->cell,
2252                                       tree_column->tree_view,
2253                                       &real_cell_area,
2254                                       &x_offset, &y_offset,
2255                                       &width, &height);
2256
2257           if (min_x > (real_cell_area.x + x_offset))
2258             min_x = real_cell_area.x + x_offset;
2259           if (max_x < real_cell_area.x + x_offset + width)
2260             max_x = real_cell_area.x + x_offset + width;
2261           if (min_y > (real_cell_area.y + y_offset))
2262             min_y = real_cell_area.y + y_offset;
2263           if (max_y < real_cell_area.y + y_offset + height)
2264             max_y = real_cell_area.y + y_offset + height;
2265         }
2266       real_cell_area.x += (info->requested_width + tree_column->spacing);
2267     }
2268   for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2269     {
2270       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2271
2272       if (info->pack == GTK_PACK_START)
2273         continue;
2274
2275       if (! info->cell->visible)
2276         continue;
2277
2278       real_cell_area.width = info->requested_width +
2279         (info->expand?extra_space:0);
2280       gtk_cell_renderer_render (info->cell,
2281                                 window,
2282                                 tree_column->tree_view,
2283                                 background_area,
2284                                 &real_cell_area,
2285                                 expose_area,
2286                                 flags);
2287       real_cell_area.x += (info->requested_width + tree_column->spacing);
2288     }
2289   if (! render)
2290     {
2291       if (min_x >= max_x || min_y >= max_y)
2292         {
2293           *focus_rectangle = *cell_area;
2294           focus_rectangle->x -= focus_line_width;
2295           focus_rectangle->y -= focus_line_width;
2296           focus_rectangle->width += 2 * focus_line_width;
2297           focus_rectangle->height += 2 * focus_line_width;
2298         }
2299       else
2300         {
2301           focus_rectangle->x = min_x - focus_line_width;
2302           focus_rectangle->y = min_y - focus_line_width;
2303           focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
2304           focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
2305         }
2306     }
2307 }
2308
2309 /**
2310  * gtk_tree_view_column_cell_render:
2311  * @tree_column: A #GtkTreeViewColumn.
2312  * @window: a #GdkDrawable to draw to
2313  * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
2314  * @cell_area: area normally rendered by a cell renderer
2315  * @expose_area: area that actually needs updating
2316  * @flags: flags that affect rendering
2317  * 
2318  * Renders the cell contained by #tree_column. This is used primarily by the
2319  * #GtkTreeView.
2320  **/
2321 void
2322 gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
2323                                   GdkWindow         *window,
2324                                   GdkRectangle      *background_area,
2325                                   GdkRectangle      *cell_area,
2326                                   GdkRectangle      *expose_area,
2327                                   guint              flags)
2328 {
2329   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2330   g_return_if_fail (background_area != NULL);
2331   g_return_if_fail (cell_area != NULL);
2332   g_return_if_fail (expose_area != NULL);
2333
2334   gtk_tree_view_column_cell_render_or_focus (tree_column,
2335                                              window,
2336                                              background_area,
2337                                              cell_area,
2338                                              expose_area,
2339                                              flags,
2340                                              TRUE,
2341                                              NULL);
2342 }
2343
2344 gboolean
2345 _gtk_tree_view_column_cell_event (GtkTreeViewColumn  *tree_column,
2346                                   GtkCellEditable   **editable_widget,
2347                                   GdkEvent           *event,
2348                                   gchar              *path_string,
2349                                   GdkRectangle       *background_area,
2350                                   GdkRectangle       *cell_area,
2351                                   guint               flags)
2352 {
2353   gboolean visible, mode;
2354
2355   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2356
2357   g_object_get (G_OBJECT (((GtkTreeViewColumnCellInfo *) tree_column->cell_list->data)->cell),
2358                 "visible", &visible,
2359                 "mode", &mode,
2360                 NULL);
2361   if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2362     {
2363       if (gtk_cell_renderer_activate (((GtkTreeViewColumnCellInfo *) tree_column->cell_list->data)->cell,
2364                                       event,
2365                                       tree_column->tree_view,
2366                                       path_string,
2367                                       background_area,
2368                                       cell_area,
2369                                       flags))
2370         return TRUE;
2371     }
2372   else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2373     {
2374       *editable_widget = gtk_cell_renderer_start_editing (((GtkTreeViewColumnCellInfo *) tree_column->cell_list->data)->cell,
2375                                                           event,
2376                                                           tree_column->tree_view,
2377                                                           path_string,
2378                                                           background_area,
2379                                                           cell_area,
2380                                                           flags);
2381
2382       if (*editable_widget != NULL)
2383         {
2384           g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2385
2386           return TRUE;
2387         }
2388     }
2389   return FALSE;
2390 }
2391
2392
2393 gboolean
2394 gtk_tree_view_column_cell_focus (GtkTreeViewColumn *tree_column,
2395                                  gint               direction)
2396 {
2397   if (GTK_TREE_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
2398     return FALSE;
2399   return TRUE;
2400 }
2401
2402 void
2403 gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn       *tree_column,
2404                                       GdkWindow               *window,
2405                                       GdkRectangle            *background_area,
2406                                       GdkRectangle            *cell_area,
2407                                       GdkRectangle            *expose_area,
2408                                       guint                    flags)
2409 {
2410   gint focus_line_width;
2411   GtkStateType cell_state;
2412   
2413   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2414   gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2415                         "focus-line-width", &focus_line_width, NULL);
2416   if (tree_column->editable_widget)
2417     {
2418       /* This function is only called on the editable row when editing.
2419        */
2420 #if 0
2421       gtk_paint_focus (tree_column->tree_view->style,
2422                        window,
2423                        GTK_WIDGET_STATE (tree_column->tree_view),
2424                        NULL,
2425                        tree_column->tree_view,
2426                        "treeview",
2427                        cell_area->x - focus_line_width,
2428                        cell_area->y - focus_line_width,
2429                        cell_area->width + 2 * focus_line_width,
2430                        cell_area->height + 2 * focus_line_width);
2431 #endif      
2432     }
2433   else
2434     {
2435       GdkRectangle focus_rectangle;
2436       gtk_tree_view_column_cell_render_or_focus (tree_column,
2437                                                  window,
2438                                                  background_area,
2439                                                  cell_area,
2440                                                  expose_area,
2441                                                  flags,
2442                                                  FALSE,
2443                                                  &focus_rectangle);
2444
2445       cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
2446               (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
2447               (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
2448       gtk_paint_focus (tree_column->tree_view->style,
2449                        window,
2450                        cell_state,
2451                        NULL,
2452                        tree_column->tree_view,
2453                        "treeview",
2454                        focus_rectangle.x,
2455                        focus_rectangle.y,
2456                        focus_rectangle.width,
2457                        focus_rectangle.height);
2458     }
2459 }
2460
2461 gboolean
2462 gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
2463 {
2464   GList *list;
2465
2466   for (list = tree_column->cell_list; list; list = list->next)
2467     {
2468       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2469
2470       if (info->cell->visible)
2471         return TRUE;
2472     }
2473
2474   return FALSE;
2475 }
2476
2477 void
2478 gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column)
2479 {
2480   GList *list;
2481
2482   for (list = tree_column->cell_list; list; list = list->next)
2483     {
2484       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2485
2486       info->requested_width = 0;
2487     }
2488   tree_column->dirty = TRUE;
2489   tree_column->requested_width = 0;
2490
2491   if (tree_column->tree_view &&
2492       GTK_WIDGET_REALIZED (tree_column->tree_view))
2493     {
2494       _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
2495       gtk_widget_queue_resize (tree_column->tree_view);
2496     }
2497 }
2498
2499 void
2500 _gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
2501                                      GtkCellEditable   *cell_editable)
2502 {
2503   g_return_if_fail (tree_column->editable_widget == NULL);
2504
2505   tree_column->editable_widget = cell_editable;
2506 }
2507
2508 void
2509 _gtk_tree_view_column_stop_editing (GtkTreeViewColumn *tree_column)
2510 {
2511   g_return_if_fail (tree_column->editable_widget != NULL);
2512
2513   tree_column->editable_widget = NULL;
2514 }