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