]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeviewcolumn.c
The "big treeview focus patch". Fixes several issues and adds some
[~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   gint real_width;
68   guint expand : 1;
69   guint pack : 1;
70   guint has_focus : 1;
71   guint in_editing_mode : 1;
72 };
73
74 /* Type methods */
75 static void gtk_tree_view_column_init                          (GtkTreeViewColumn       *tree_column);
76 static void gtk_tree_view_column_class_init                    (GtkTreeViewColumnClass  *klass);
77
78 /* GObject methods */
79 static void gtk_tree_view_column_set_property                  (GObject                 *object,
80                                                                 guint                    prop_id,
81                                                                 const GValue            *value,
82                                                                 GParamSpec              *pspec);
83 static void gtk_tree_view_column_get_property                  (GObject                 *object,
84                                                                 guint                    prop_id,
85                                                                 GValue                  *value,
86                                                                 GParamSpec              *pspec);
87 static void gtk_tree_view_column_finalize                      (GObject                 *object);
88
89 /* Button handling code */ 
90 static void gtk_tree_view_column_create_button                 (GtkTreeViewColumn       *tree_column);
91 static void gtk_tree_view_column_update_button                 (GtkTreeViewColumn       *tree_column);
92
93 /* Button signal handlers */
94 static gint gtk_tree_view_column_button_event                  (GtkWidget               *widget,
95                                                                 GdkEvent                *event,
96                                                                 gpointer                 data);
97 static void gtk_tree_view_column_button_clicked                (GtkWidget               *widget,
98                                                                 gpointer                 data);
99 static gboolean gtk_tree_view_column_mnemonic_activate         (GtkWidget *widget,
100                                                                 gboolean   group_cycling,
101                                                                 gpointer   data);
102
103 /* Property handlers */
104 static void gtk_tree_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
105                                                                 GtkTreeViewColumn       *tree_column);
106
107 /* Internal functions */
108 static void gtk_tree_view_column_sort                          (GtkTreeViewColumn       *tree_column,
109                                                                 gpointer                 data);
110 static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn       *tree_column);
111 static void gtk_tree_view_column_set_attributesv               (GtkTreeViewColumn       *tree_column,
112                                                                 GtkCellRenderer         *cell_renderer,
113                                                                 va_list                  args);
114 static GtkTreeViewColumnCellInfo *gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
115                                                                       GtkCellRenderer   *cell_renderer);
116
117 /* cell list manipulation */
118 static GList *gtk_tree_view_column_cell_first                  (GtkTreeViewColumn      *tree_column);
119 static GList *gtk_tree_view_column_cell_last                   (GtkTreeViewColumn      *tree_column);
120 static GList *gtk_tree_view_column_cell_next                   (GtkTreeViewColumn      *tree_column,
121                                                                 GList                  *current);
122 static GList *gtk_tree_view_column_cell_prev                   (GtkTreeViewColumn      *tree_column,
123                                                                 GList                  *current);
124
125
126 static GtkObjectClass *parent_class = NULL;
127 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
128
129
130 GtkType
131 gtk_tree_view_column_get_type (void)
132 {
133   static GtkType tree_column_type = 0;
134
135   if (!tree_column_type)
136     {
137       static const GTypeInfo tree_column_info =
138       {
139         sizeof (GtkTreeViewColumnClass),
140         NULL,           /* base_init */
141         NULL,           /* base_finalize */
142         (GClassInitFunc) gtk_tree_view_column_class_init,
143         NULL,           /* class_finalize */
144         NULL,           /* class_data */
145         sizeof (GtkTreeViewColumn),
146         0,
147         (GInstanceInitFunc) gtk_tree_view_column_init,
148       };
149
150       tree_column_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn", &tree_column_info, 0);
151     }
152
153   return tree_column_type;
154 }
155
156 static void
157 gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
158 {
159   GObjectClass *object_class;
160
161   object_class = (GObjectClass*) class;
162
163   parent_class = g_type_class_peek_parent (class);
164
165   class->clicked = NULL;
166
167   object_class->finalize = gtk_tree_view_column_finalize;
168   object_class->set_property = gtk_tree_view_column_set_property;
169   object_class->get_property = gtk_tree_view_column_get_property;
170   
171   tree_column_signals[CLICKED] =
172     g_signal_new ("clicked",
173                   GTK_CLASS_TYPE (object_class),
174                   G_SIGNAL_RUN_LAST,
175                   G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
176                   NULL, NULL,
177                   _gtk_marshal_VOID__VOID,
178                   GTK_TYPE_NONE, 0);
179
180   g_object_class_install_property (object_class,
181                                    PROP_VISIBLE,
182                                    g_param_spec_boolean ("visible",
183                                                         _("Visible"),
184                                                         _("Whether to display the column"),
185                                                          TRUE,
186                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
187   
188   g_object_class_install_property (object_class,
189                                    PROP_RESIZABLE,
190                                    g_param_spec_boolean ("resizable",
191                                                          _("Resizable"),
192                                                          _("Column is user-resizable"),
193                                                          FALSE,
194                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
195   
196   g_object_class_install_property (object_class,
197                                    PROP_WIDTH,
198                                    g_param_spec_int ("width",
199                                                      _("Width"),
200                                                      _("Current width of the column"),
201                                                      0,
202                                                      G_MAXINT,
203                                                      0,
204                                                      G_PARAM_READABLE));
205   g_object_class_install_property (object_class,
206                                    PROP_SIZING,
207                                    g_param_spec_enum ("sizing",
208                                                       _("Sizing"),
209                                                       _("Resize mode of the column"),
210                                                       GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
211                                                       GTK_TREE_VIEW_COLUMN_AUTOSIZE,
212                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
213   
214   g_object_class_install_property (object_class,
215                                    PROP_FIXED_WIDTH,
216                                    g_param_spec_int ("fixed_width",
217                                                      _("Fixed Width"),
218                                                      _("Current fixed width of the column"),
219                                                      1,
220                                                      G_MAXINT,
221                                                      1, /* not useful */
222                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
223
224   g_object_class_install_property (object_class,
225                                    PROP_MIN_WIDTH,
226                                    g_param_spec_int ("min_width",
227                                                      _("Minimum Width"),
228                                                      _("Minimum 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_MAX_WIDTH,
236                                    g_param_spec_int ("max_width",
237                                                      _("Maximum Width"),
238                                                      _("Maximum allowed width of the column"),
239                                                      -1,
240                                                      G_MAXINT,
241                                                      -1,
242                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
243
244   g_object_class_install_property (object_class,
245                                    PROP_TITLE,
246                                    g_param_spec_string ("title",
247                                                         _("Title"),
248                                                         _("Title to appear in column header"),
249                                                         "",
250                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
251   
252   g_object_class_install_property (object_class,
253                                    PROP_CLICKABLE,
254                                    g_param_spec_boolean ("clickable",
255                                                         _("Clickable"),
256                                                         _("Whether the header can be clicked"),
257                                                          TRUE,
258                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
259   
260
261   g_object_class_install_property (object_class,
262                                    PROP_WIDGET,
263                                    g_param_spec_object ("widget",
264                                                         _("Widget"),
265                                                         _("Widget to put in column header button instead of column title"),
266                                                         GTK_TYPE_WIDGET,
267                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
268
269   g_object_class_install_property (object_class,
270                                    PROP_ALIGNMENT,
271                                    g_param_spec_float ("alignment",
272                                                        _("Alignment"),
273                                                        _("X Alignment of the column header text or widget"),
274                                                        0.0,
275                                                        1.0,
276                                                        0.5,
277                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
278
279   g_object_class_install_property (object_class,
280                                    PROP_REORDERABLE,
281                                    g_param_spec_boolean ("reorderable",
282                                                          _("Reorderable"),
283                                                          _("Whether the column can be reordered around the headers"),
284                                                          FALSE,
285                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
286
287   g_object_class_install_property (object_class,
288                                    PROP_SORT_INDICATOR,
289                                    g_param_spec_boolean ("sort_indicator",
290                                                         _("Sort indicator"),
291                                                         _("Whether to show a sort indicator"),
292                                                          FALSE,
293                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
294
295   g_object_class_install_property (object_class,
296                                    PROP_SORT_ORDER,
297                                    g_param_spec_enum ("sort_order",
298                                                       _("Sort order"),
299                                                       _("Sort direction the sort indicator should indicate"),
300                                                       GTK_TYPE_SORT_TYPE,
301                                                       GTK_SORT_ASCENDING,
302                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
303   
304 }
305
306 static void
307 gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
308 {
309   tree_column->button = NULL;
310   tree_column->xalign = 0.0;
311   tree_column->width = 0;
312   tree_column->requested_width = -1;
313   tree_column->min_width = -1;
314   tree_column->max_width = -1;
315   tree_column->resized_width = 0;
316   tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
317   tree_column->visible = TRUE;
318   tree_column->resizable = FALSE;
319   tree_column->clickable = FALSE;
320   tree_column->dirty = TRUE;
321   tree_column->sort_order = GTK_SORT_ASCENDING;
322   tree_column->show_sort_indicator = FALSE;
323   tree_column->property_changed_signal = 0;
324   tree_column->sort_clicked_signal = 0;
325   tree_column->sort_column_changed_signal = 0;
326   tree_column->sort_column_id = -1;
327   tree_column->reorderable = FALSE;
328   tree_column->maybe_reordered = FALSE;
329   tree_column->use_resized_width = FALSE;
330 }
331
332 static void
333 gtk_tree_view_column_finalize (GObject *object)
334 {
335   GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
336   GList *list;
337
338   for (list = tree_column->cell_list; list; list = list->next)
339     {
340       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
341
342       if (info->destroy)
343         {
344           GtkDestroyNotify d = info->destroy;
345
346           info->destroy = NULL;
347           d (info->func_data);
348         }
349       gtk_tree_view_column_clear_attributes (tree_column, info->cell);
350       g_object_unref (G_OBJECT (info->cell));
351       g_free (info);
352     }
353
354   g_free (tree_column->title);
355
356   G_OBJECT_CLASS (parent_class)->finalize (object);
357 }
358
359 static void
360 gtk_tree_view_column_set_property (GObject         *object,
361                                    guint            prop_id,
362                                    const GValue    *value,
363                                    GParamSpec      *pspec)
364 {
365   GtkTreeViewColumn *tree_column;
366
367   tree_column = GTK_TREE_VIEW_COLUMN (object);
368
369   switch (prop_id)
370     {
371     case PROP_VISIBLE:
372       gtk_tree_view_column_set_visible (tree_column,
373                                         g_value_get_boolean (value));
374       break;
375
376     case PROP_RESIZABLE:
377       gtk_tree_view_column_set_resizable (tree_column,
378                                           g_value_get_boolean (value));
379       break;
380
381     case PROP_SIZING:
382       gtk_tree_view_column_set_sizing (tree_column,
383                                        g_value_get_enum (value));
384       break;
385
386     case PROP_FIXED_WIDTH:
387       gtk_tree_view_column_set_fixed_width (tree_column,
388                                             g_value_get_int (value));
389       break;
390
391     case PROP_MIN_WIDTH:
392       gtk_tree_view_column_set_min_width (tree_column,
393                                           g_value_get_int (value));
394       break;
395
396     case PROP_MAX_WIDTH:
397       gtk_tree_view_column_set_max_width (tree_column,
398                                           g_value_get_int (value));
399       break;
400
401     case PROP_TITLE:
402       gtk_tree_view_column_set_title (tree_column,
403                                       g_value_get_string (value));
404       break;
405
406     case PROP_CLICKABLE:
407       gtk_tree_view_column_set_clickable (tree_column,
408                                           g_value_get_boolean (value));
409       break;
410
411     case PROP_WIDGET:
412       gtk_tree_view_column_set_widget (tree_column,
413                                        (GtkWidget*) g_value_get_object (value));
414       break;
415
416     case PROP_ALIGNMENT:
417       gtk_tree_view_column_set_alignment (tree_column,
418                                           g_value_get_float (value));
419       break;
420
421     case PROP_REORDERABLE:
422       gtk_tree_view_column_set_reorderable (tree_column,
423                                             g_value_get_boolean (value));
424       break;
425
426     case PROP_SORT_INDICATOR:
427       gtk_tree_view_column_set_sort_indicator (tree_column,
428                                                g_value_get_boolean (value));
429       break;
430
431     case PROP_SORT_ORDER:
432       gtk_tree_view_column_set_sort_order (tree_column,
433                                            g_value_get_enum (value));
434       break;
435       
436     default:
437       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
438       break;
439     }
440 }
441
442 static void
443 gtk_tree_view_column_get_property (GObject         *object,
444                                    guint            prop_id,
445                                    GValue          *value,
446                                    GParamSpec      *pspec)
447 {
448   GtkTreeViewColumn *tree_column;
449
450   tree_column = GTK_TREE_VIEW_COLUMN (object);
451
452   switch (prop_id)
453     {
454     case PROP_VISIBLE:
455       g_value_set_boolean (value,
456                            gtk_tree_view_column_get_visible (tree_column));
457       break;
458
459     case PROP_RESIZABLE:
460       g_value_set_boolean (value,
461                            gtk_tree_view_column_get_resizable (tree_column));
462       break;
463
464     case PROP_WIDTH:
465       g_value_set_int (value,
466                        gtk_tree_view_column_get_width (tree_column));
467       break;
468
469     case PROP_SIZING:
470       g_value_set_enum (value,
471                         gtk_tree_view_column_get_sizing (tree_column));
472       break;
473
474     case PROP_FIXED_WIDTH:
475       g_value_set_int (value,
476                        gtk_tree_view_column_get_fixed_width (tree_column));
477       break;
478
479     case PROP_MIN_WIDTH:
480       g_value_set_int (value,
481                        gtk_tree_view_column_get_min_width (tree_column));
482       break;
483
484     case PROP_MAX_WIDTH:
485       g_value_set_int (value,
486                        gtk_tree_view_column_get_max_width (tree_column));
487       break;
488
489     case PROP_TITLE:
490       g_value_set_string (value,
491                           gtk_tree_view_column_get_title (tree_column));
492       break;
493
494     case PROP_CLICKABLE:
495       g_value_set_boolean (value,
496                            gtk_tree_view_column_get_clickable (tree_column));
497       break;
498
499     case PROP_WIDGET:
500       g_value_set_object (value,
501                           (GObject*) gtk_tree_view_column_get_widget (tree_column));
502       break;
503
504     case PROP_ALIGNMENT:
505       g_value_set_float (value,
506                          gtk_tree_view_column_get_alignment (tree_column));
507       break;
508
509     case PROP_REORDERABLE:
510       g_value_set_boolean (value,
511                            gtk_tree_view_column_get_reorderable (tree_column));
512       break;
513
514     case PROP_SORT_INDICATOR:
515       g_value_set_boolean (value,
516                            gtk_tree_view_column_get_sort_indicator (tree_column));
517       break;
518
519     case PROP_SORT_ORDER:
520       g_value_set_enum (value,
521                         gtk_tree_view_column_get_sort_order (tree_column));
522       break;
523       
524     default:
525       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
526       break;
527     }
528 }
529
530 /* Helper functions
531  */
532
533 /* Button handling code
534  */
535 static void
536 gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
537 {
538   GtkTreeView *tree_view;
539   GtkWidget *child;
540   GtkWidget *hbox;
541
542   tree_view = (GtkTreeView *) tree_column->tree_view;
543
544   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
545   g_return_if_fail (tree_column->button == NULL);
546
547   gtk_widget_push_composite_child ();
548   tree_column->button = gtk_button_new ();
549   gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
550   gtk_widget_pop_composite_child ();
551
552   /* make sure we own a reference to it as well. */
553   if (tree_view->priv->header_window)
554     gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
555   gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
556
557   g_signal_connect (G_OBJECT (tree_column->button), "event",
558                     G_CALLBACK (gtk_tree_view_column_button_event),
559                     (gpointer) tree_column);
560   g_signal_connect (G_OBJECT (tree_column->button), "clicked",
561                     (GtkSignalFunc) gtk_tree_view_column_button_clicked,
562                     (gpointer) tree_column);
563
564   tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
565
566   hbox = gtk_hbox_new (FALSE, 2);
567   tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
568
569   if (tree_column->child)
570     child = tree_column->child;
571   else
572     {
573       child = gtk_label_new (tree_column->title);
574       gtk_widget_show (child);
575     }
576
577   g_signal_connect (G_OBJECT (child), "mnemonic_activate",
578                     G_CALLBACK (gtk_tree_view_column_mnemonic_activate),
579                     (gpointer) tree_column);
580
581   if (tree_column->xalign <= 0.5)
582     gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
583   else
584     gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
585
586   gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
587         
588   gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
589   gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
590
591   gtk_widget_show (hbox);
592   gtk_widget_show (tree_column->alignment);
593   gtk_tree_view_column_update_button (tree_column);
594 }
595
596 static void 
597 gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
598 {
599   GtkWidget *hbox;
600   GtkWidget *alignment;
601   GtkWidget *arrow;
602   GtkWidget *current_child;
603
604   /* Create a button if necessary */
605   if (tree_column->visible &&
606       tree_column->button == NULL &&
607       tree_column->tree_view &&
608       GTK_WIDGET_REALIZED (tree_column->tree_view))
609     gtk_tree_view_column_create_button (tree_column);
610   
611   if (! tree_column->button)
612     return;
613
614   hbox = GTK_BIN (tree_column->button)->child;
615   alignment = tree_column->alignment;
616   arrow = tree_column->arrow;
617   current_child = GTK_BIN (alignment)->child;
618
619   /* Set up the actual button */
620   gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
621                      0.5, 0.0, 0.0);
622       
623   if (tree_column->child)
624     {
625       if (current_child != tree_column->child)
626         {
627           gtk_container_remove (GTK_CONTAINER (alignment),
628                                 current_child);
629           gtk_container_add (GTK_CONTAINER (alignment),
630                              tree_column->child);
631         }
632     }
633   else 
634     {
635       if (current_child == NULL)
636         {
637           current_child = gtk_label_new (NULL);
638           gtk_widget_show (current_child);
639           gtk_container_add (GTK_CONTAINER (alignment),
640                              current_child);
641         }
642
643       g_return_if_fail (GTK_IS_LABEL (current_child));
644
645       if (tree_column->title)
646         gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
647                                           tree_column->title);
648       else
649         gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
650                                           "");
651     }
652
653   switch (tree_column->sort_order)
654     {
655     case GTK_SORT_ASCENDING:
656       gtk_arrow_set (GTK_ARROW (arrow),
657                      GTK_ARROW_DOWN,
658                      GTK_SHADOW_IN);
659       break;
660
661     case GTK_SORT_DESCENDING:
662       gtk_arrow_set (GTK_ARROW (arrow),
663                      GTK_ARROW_UP,
664                      GTK_SHADOW_IN);
665       break;
666           
667     default:
668       g_warning (G_STRLOC": bad sort order");
669       break;
670     }
671
672   /* Put arrow on the right if the text is left-or-center justified, and on the
673    * left otherwise; do this by packing boxes, so flipping text direction will
674    * reverse things
675    */
676   gtk_widget_ref (arrow);
677   gtk_container_remove (GTK_CONTAINER (hbox), arrow);
678
679   if (tree_column->xalign <= 0.5)
680     {
681       gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
682     }
683   else
684     {
685       gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
686       /* move it to the front */
687       gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
688     }
689   gtk_widget_unref (arrow);
690
691   if (tree_column->show_sort_indicator)
692     gtk_widget_show (arrow);
693   else
694     gtk_widget_hide (arrow);
695
696   /* It's always safe to hide the button.  It isn't always safe to show it, as
697    * if you show it before it's realized, it'll get the wrong window. */
698   if (tree_column->button &&
699       tree_column->tree_view != NULL &&
700       GTK_WIDGET_REALIZED (tree_column->tree_view))
701     {
702       if (tree_column->visible)
703         {
704           gtk_widget_show_now (tree_column->button);
705           if (tree_column->window)
706             {
707               if (tree_column->resizable)
708                 {
709                   gdk_window_show (tree_column->window);
710                   gdk_window_raise (tree_column->window);
711                 }
712               else
713                 {
714                   gdk_window_hide (tree_column->window);
715                 }
716             }
717         }
718       else
719         {
720           gtk_widget_hide (tree_column->button);
721           if (tree_column->window)
722             gdk_window_hide (tree_column->window);
723         }
724     }
725   
726   if (tree_column->reorderable || tree_column->clickable)
727     {
728       GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
729     }
730   else
731     {
732       GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
733       if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
734         {
735           GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
736           if (GTK_WIDGET_TOPLEVEL (toplevel))
737             {
738               gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
739             }
740         }
741     }
742   /* Queue a resize on the assumption that we always want to catch all changes
743    * and columns don't change all that often.
744    */
745   if (GTK_WIDGET_REALIZED (tree_column->tree_view))
746      gtk_widget_queue_resize (tree_column->tree_view);
747
748 }
749
750 /* Button signal handlers
751  */
752
753 static gint
754 gtk_tree_view_column_button_event (GtkWidget *widget,
755                                    GdkEvent  *event,
756                                    gpointer   data)
757 {
758   GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
759
760   g_return_val_if_fail (event != NULL, FALSE);
761
762   if (event->type == GDK_BUTTON_PRESS &&
763       column->reorderable)
764     {
765       column->maybe_reordered = TRUE;
766       gdk_window_get_pointer (widget->window,
767                               &column->drag_x,
768                               &column->drag_y,
769                               NULL);
770       gtk_widget_grab_focus (widget);
771     }
772
773   if (event->type == GDK_BUTTON_RELEASE &&
774       column->maybe_reordered)
775     column->maybe_reordered = FALSE;
776
777   if (event->type == GDK_MOTION_NOTIFY &&
778       (column->maybe_reordered) &&
779       (gtk_drag_check_threshold (widget,
780                                  column->drag_x,
781                                  column->drag_y,
782                                  (gint) ((GdkEventMotion *)event)->x,
783                                  (gint) ((GdkEventMotion *)event)->y)))
784     {
785       column->maybe_reordered = FALSE;
786       /* this is to change our drag_x to be relative to
787        * tree_view->priv->bin_window, instead of our window.
788        */
789       column->drag_x -= column->button->allocation.x;
790       _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
791       return TRUE;
792     }
793   if (column->clickable == FALSE)
794     {
795       switch (event->type)
796         {
797         case GDK_BUTTON_PRESS:
798         case GDK_2BUTTON_PRESS:
799         case GDK_3BUTTON_PRESS:
800         case GDK_MOTION_NOTIFY:
801         case GDK_BUTTON_RELEASE:
802         case GDK_ENTER_NOTIFY:
803         case GDK_LEAVE_NOTIFY:
804           return TRUE;
805         default:
806           return FALSE;
807         }
808     }
809   return FALSE;
810 }
811
812
813 static void
814 gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
815 {
816   g_signal_emit_by_name (G_OBJECT (data), "clicked");
817 }
818
819 static gboolean
820 gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
821                                         gboolean   group_cycling,
822                                         gpointer   data)
823 {
824   GtkTreeViewColumn *column = (GtkTreeViewColumn *)data;
825
826   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), FALSE);
827
828   GTK_TREE_VIEW (column->tree_view)->priv->focus_column = column;
829   if (column->clickable)
830     gtk_button_clicked (GTK_BUTTON (column->button));
831   else if (GTK_WIDGET_CAN_FOCUS (column->button))
832     gtk_widget_grab_focus (column->button);
833   else
834     gtk_widget_grab_focus (column->tree_view);
835
836   return TRUE;
837 }
838
839 static void
840 gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
841                                          GtkTreeViewColumn *column)
842 {
843   gint sort_column_id;
844   GtkSortType order;
845
846   if (gtk_tree_sortable_get_sort_column_id (sortable,
847                                             &sort_column_id,
848                                             &order))
849     {
850       if (sort_column_id == column->sort_column_id)
851         {
852           gtk_tree_view_column_set_sort_indicator (column, TRUE);
853           gtk_tree_view_column_set_sort_order (column, order);
854         }
855       else
856         {
857           gtk_tree_view_column_set_sort_indicator (column, FALSE);
858         }
859     }
860   else
861     {
862       gtk_tree_view_column_set_sort_indicator (column, FALSE);
863     }
864 }
865
866 static void
867 gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
868                            gpointer           data)
869 {
870   gint sort_column_id;
871   GtkSortType order;
872   gboolean has_sort_column;
873   gboolean has_default_sort_func;
874
875   g_return_if_fail (tree_column->tree_view != NULL);
876
877   has_sort_column =
878     gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
879                                           &sort_column_id,
880                                           &order);
881   has_default_sort_func =
882     gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model));
883
884   if (has_sort_column &&
885       sort_column_id == tree_column->sort_column_id)
886     {
887       if (order == GTK_SORT_ASCENDING)
888         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
889                                               tree_column->sort_column_id,
890                                               GTK_SORT_DESCENDING);
891       else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
892         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
893                                               GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
894                                               GTK_SORT_ASCENDING);
895       else
896         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
897                                               tree_column->sort_column_id,
898                                               GTK_SORT_ASCENDING);
899     }
900   else
901     {
902       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
903                                             tree_column->sort_column_id,
904                                             GTK_SORT_ASCENDING);
905     }
906 }
907
908
909 static void
910 gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
911 {
912   GtkTreeModel *model;
913
914   if (tree_column->tree_view == NULL)
915     return;
916
917   model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
918
919   if (model == NULL)
920     return;
921
922   if (GTK_IS_TREE_SORTABLE (model) &&
923       tree_column->sort_column_id != -1)
924     {
925       gint real_sort_column_id;
926       GtkSortType real_order;
927
928       if (tree_column->sort_column_changed_signal == 0)
929         tree_column->sort_column_changed_signal =
930           g_signal_connect (G_OBJECT (model), "sort_column_changed",
931                             GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed),
932                             tree_column);
933       
934       if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
935                                                 &real_sort_column_id,
936                                                 &real_order) &&
937           (real_sort_column_id == tree_column->sort_column_id))
938         {
939           gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
940           gtk_tree_view_column_set_sort_order (tree_column, real_order);
941
942           return;
943         }
944     }
945 }
946
947
948 /* Exported Private Functions.
949  * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
950  */
951
952 void
953 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
954 {
955   GtkTreeView *tree_view;
956   GdkWindowAttr attr;
957   guint attributes_mask;
958
959   tree_view = (GtkTreeView *)column->tree_view;
960
961   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
962   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
963   g_return_if_fail (tree_view->priv->header_window != NULL);
964   g_return_if_fail (column->button != NULL);
965
966   gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
967
968   if (column->visible)
969     gtk_widget_show (column->button);
970
971   attr.window_type = GDK_WINDOW_CHILD;
972   attr.wclass = GDK_INPUT_ONLY;
973   attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
974   attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
975   attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
976   attr.event_mask = (GDK_BUTTON_PRESS_MASK |
977                      GDK_BUTTON_RELEASE_MASK |
978                      GDK_POINTER_MOTION_MASK |
979                      GDK_POINTER_MOTION_HINT_MASK |
980                      GDK_KEY_PRESS_MASK);
981   attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
982   attr.cursor = gdk_cursor_new_for_screen (gdk_drawable_get_screen (tree_view->priv->header_window),
983                                            GDK_SB_H_DOUBLE_ARROW);
984   attr.y = 0;
985   attr.width = TREE_VIEW_DRAG_WIDTH;
986   attr.height = tree_view->priv->header_height;
987
988   attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
989           
990   column->window = gdk_window_new (tree_view->priv->header_window,
991                                    &attr, attributes_mask);
992   gdk_window_set_user_data (column->window, tree_view);
993
994   gtk_tree_view_column_update_button (column);
995
996   gdk_cursor_unref (attr.cursor);
997 }
998
999 void
1000 _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
1001 {
1002   g_return_if_fail (column != NULL);
1003   g_return_if_fail (column->window != NULL);
1004
1005   gdk_window_set_user_data (column->window, NULL);
1006   gdk_window_destroy (column->window);
1007   column->window = NULL;
1008 }
1009
1010 void
1011 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
1012                                      GtkTreeView       *tree_view)
1013 {
1014   g_assert (column->tree_view == NULL);
1015
1016   column->tree_view = GTK_WIDGET (tree_view);
1017   gtk_tree_view_column_create_button (column);
1018
1019   column->property_changed_signal =
1020           g_signal_connect_swapped (GTK_OBJECT (tree_view),
1021                                     "notify::model",
1022                                     GTK_SIGNAL_FUNC (gtk_tree_view_column_setup_sort_column_id_callback),
1023                                     column);
1024
1025   gtk_tree_view_column_setup_sort_column_id_callback (column);
1026 }
1027
1028 void
1029 _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
1030 {
1031   if (column->tree_view && column->button)
1032     {
1033       gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1034     }
1035   if (column->property_changed_signal)
1036     {
1037       g_signal_handler_disconnect (G_OBJECT (column->tree_view), column->property_changed_signal);
1038       column->property_changed_signal = 0;
1039     }
1040
1041   if (column->sort_column_changed_signal)
1042     {
1043       g_signal_handler_disconnect (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view))),
1044                                    column->sort_column_changed_signal);
1045       column->sort_column_changed_signal = 0;
1046     }
1047
1048   column->tree_view = NULL;
1049   column->button = NULL;
1050 }
1051
1052 gboolean
1053 _gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column)
1054 {
1055   GList *list;
1056
1057   for (list = column->cell_list; list; list = list->next)
1058     if (((GtkTreeViewColumnCellInfo *)list->data)->cell->mode ==
1059         GTK_CELL_RENDERER_MODE_EDITABLE)
1060       return TRUE;
1061
1062   return FALSE;
1063 }
1064
1065 /* gets cell being edited */
1066 GtkCellRenderer *
1067 _gtk_tree_view_column_get_edited_cell (GtkTreeViewColumn *column)
1068 {
1069   GList *list;
1070
1071   for (list = column->cell_list; list; list = list->next)
1072     if (((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode)
1073       return ((GtkTreeViewColumnCellInfo *)list->data)->cell;
1074
1075   return NULL;
1076 }
1077
1078 gint
1079 _gtk_tree_view_column_count_special_cells (GtkTreeViewColumn *column)
1080 {
1081   gint i = 0;
1082   GList *list;
1083
1084   for (list = column->cell_list; list; list = list->next)
1085     {
1086       GtkTreeViewColumnCellInfo *cellinfo = list->data;
1087
1088       if (cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1089           cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
1090         i++;
1091     }
1092
1093   return i;
1094 }
1095
1096 GtkCellRenderer *
1097 _gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column,
1098                                        gint               x)
1099 {
1100   GList *list;
1101   gint current_x = 0;
1102
1103   list = gtk_tree_view_column_cell_first (column);
1104   for (; list; list = gtk_tree_view_column_cell_next (column, list))
1105    {
1106      GtkTreeViewColumnCellInfo *cellinfo = list->data;
1107      if (current_x <= x && x <= current_x + cellinfo->real_width)
1108        return cellinfo->cell;
1109      current_x += cellinfo->real_width;
1110    }
1111
1112   return NULL;
1113 }
1114
1115 /* Public Functions */
1116
1117
1118 /**
1119  * gtk_tree_view_column_new:
1120  * 
1121  * Creates a new #GtkTreeViewColumn.
1122  * 
1123  * Return value: A newly created #GtkTreeViewColumn.
1124  **/
1125 GtkTreeViewColumn *
1126 gtk_tree_view_column_new (void)
1127 {
1128   GtkTreeViewColumn *tree_column;
1129
1130   tree_column = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
1131
1132   return tree_column;
1133 }
1134
1135 /**
1136  * gtk_tree_view_column_new_with_attributes:
1137  * @title: The title to set the header to.
1138  * @cell: The #GtkCellRenderer.
1139  * @Varargs: A %NULL-terminated list of attributes.
1140  * 
1141  * Creates a new #GtkTreeViewColumn with a number of default values.  This is
1142  * equivalent to calling gtk_tree_view_column_set_title(),
1143  * gtk_tree_view_column_pack_start(), and
1144  * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
1145  *
1146  * Here's a simple example:
1147  * <informalexample><programlisting>
1148  *  enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1149  *  ...
1150  *  {
1151  *    GtkTreeViewColumn *column;
1152  *    GtkCellRenderer   *renderer = gtk_cell_renderer_text_new (<!-- -->);
1153  *  
1154  *    column = gtk_tree_view_column_new_with_attributes ("Title",
1155  *                                                       renderer,
1156  *                                                       "text", TEXT_COLUMN,
1157  *                                                       "foreground", COLOR_COLUMN,
1158  *                                                       NULL);
1159  *  }
1160  * </programlisting></informalexample>
1161  * 
1162  * Return value: A newly created #GtkTreeViewColumn.
1163  **/
1164 GtkTreeViewColumn *
1165 gtk_tree_view_column_new_with_attributes (const gchar     *title,
1166                                           GtkCellRenderer *cell,
1167                                           ...)
1168 {
1169   GtkTreeViewColumn *retval;
1170   va_list args;
1171
1172   retval = gtk_tree_view_column_new ();
1173
1174   gtk_tree_view_column_set_title (retval, title);
1175   gtk_tree_view_column_pack_start (retval, cell, TRUE);
1176
1177   va_start (args, cell);
1178   gtk_tree_view_column_set_attributesv (retval, cell, args);
1179   va_end (args);
1180
1181   return retval;
1182 }
1183
1184 static GtkTreeViewColumnCellInfo *
1185 gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
1186                                     GtkCellRenderer   *cell_renderer)
1187 {
1188   GList *list;
1189   for (list = tree_column->cell_list; list; list = list->next)
1190     if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer)
1191       return (GtkTreeViewColumnCellInfo *) list->data;
1192   return NULL;
1193 }
1194
1195
1196 /**
1197  * gtk_tree_view_column_pack_start:
1198  * @tree_column: A #GtkTreeViewColumn.
1199  * @cell: The #GtkCellRenderer. 
1200  * @expand: %TRUE if @cell is to be given extra space allocated to box.
1201  *
1202  * Packs the @cell into the beginning column.  If @expand is %TRUE, then the
1203  * @cell is allocated a share of all available space that the @tree_column has.
1204  **/
1205 void
1206 gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
1207                                  GtkCellRenderer   *cell,
1208                                  gboolean           expand)
1209 {
1210   GtkTreeViewColumnCellInfo *cell_info;
1211
1212   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1213   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1214   g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1215
1216   g_object_ref (G_OBJECT (cell));
1217   gtk_object_sink (GTK_OBJECT (cell));
1218
1219   cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1220   cell_info->cell = cell;
1221   cell_info->expand = expand ? TRUE : FALSE;
1222   cell_info->pack = GTK_PACK_START;
1223   cell_info->has_focus = 0;
1224   cell_info->attributes = NULL;
1225
1226   tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1227 }
1228
1229 /**
1230  * gtk_tree_view_column_pack_end:
1231  * @tree_column: A #GtkTreeViewColumn.
1232  * @cell: The #GtkCellRenderer. 
1233  * @expand: %TRUE if @cell is to be given extra space allocated to box.
1234  *
1235  * Packs the @cell into the column.  If @expand is %TRUE, then the @cell is
1236  * allocated a share of all available space that the @tree_column has.
1237  **/
1238 void
1239 gtk_tree_view_column_pack_end (GtkTreeViewColumn  *tree_column,
1240                                GtkCellRenderer    *cell,
1241                                gboolean            expand)
1242 {
1243   GtkTreeViewColumnCellInfo *cell_info;
1244
1245   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1246   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1247   g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1248
1249   g_object_ref (G_OBJECT (cell));
1250   gtk_object_sink (GTK_OBJECT (cell));
1251
1252   cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1253   cell_info->cell = cell;
1254   cell_info->expand = expand ? TRUE : FALSE;
1255   cell_info->pack = GTK_PACK_END;
1256   cell_info->has_focus = 0;
1257   cell_info->attributes = NULL;
1258
1259   tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1260 }
1261
1262
1263 /**
1264  * gtk_tree_view_column_clear:
1265  * @tree_column: A #GtkTreeViewColumn
1266  * 
1267  * Unsets all the mappings on all renderers on the @tree_column.
1268  **/
1269 void
1270 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1271 {
1272   GList *list;
1273   g_return_if_fail (tree_column != NULL);
1274
1275   for (list = tree_column->cell_list; list; list = list->next)
1276     {
1277       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1278
1279       gtk_tree_view_column_clear_attributes (tree_column, info->cell);
1280       g_object_unref (G_OBJECT (info->cell));
1281       g_free (info);
1282     }
1283
1284   g_list_free (tree_column->cell_list);
1285   tree_column->cell_list = NULL;
1286 }
1287
1288 /**
1289  * gtk_tree_view_column_get_cell_renderers:
1290  * @tree_column: A #GtkTreeViewColumn
1291  * 
1292  * Returns a newly-allocated #GList of all the cell renderers in the column, 
1293  * in no particular order.  The list must be freed with g_list_free().
1294  * 
1295  * Return value: A list of #GtkCellRenderers
1296  **/
1297 GList *
1298 gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
1299 {
1300   GList *retval = NULL, *list;
1301
1302   g_return_val_if_fail (tree_column != NULL, NULL);
1303
1304   for (list = tree_column->cell_list; list; list = list->next)
1305     {
1306       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1307
1308       retval = g_list_append (retval, info->cell);
1309     }
1310
1311   return retval;
1312 }
1313
1314 /**
1315  * gtk_tree_view_column_add_attribute:
1316  * @tree_column: A #GtkTreeViewColumn.
1317  * @cell_renderer: the #GtkCellRenderer to set attributes on
1318  * @attribute: An attribute on the renderer
1319  * @column: The column position on the model to get the attribute from.
1320  * 
1321  * Adds an attribute mapping to the list in @tree_column.  The @column is the
1322  * column of the model to get a value from, and the @attribute is the
1323  * parameter on @cell_renderer to be set from the value. So for example
1324  * if column 2 of the model contains strings, you could have the
1325  * "text" attribute of a #GtkCellRendererText get its values from
1326  * column 2.
1327  **/
1328 void
1329 gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1330                                     GtkCellRenderer   *cell_renderer,
1331                                     const gchar       *attribute,
1332                                     gint               column)
1333 {
1334   GtkTreeViewColumnCellInfo *info;
1335
1336   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1337   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1338   g_return_if_fail (info != NULL);
1339
1340   info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
1341   info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
1342
1343   if (tree_column->tree_view)
1344     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1345
1346 }
1347
1348 static void
1349 gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
1350                                       GtkCellRenderer   *cell_renderer,
1351                                       va_list            args)
1352 {
1353   gchar *attribute;
1354   gint column;
1355
1356   attribute = va_arg (args, gchar *);
1357
1358   gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1359   
1360   while (attribute != NULL)
1361     {
1362       column = va_arg (args, gint);
1363       gtk_tree_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1364       attribute = va_arg (args, gchar *);
1365     }
1366 }
1367
1368 /**
1369  * gtk_tree_view_column_set_attributes:
1370  * @tree_column: A #GtkTreeViewColumn.
1371  * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1372  * @Varargs: A %NULL-terminated list of attributes.
1373  * 
1374  * Sets the attributes in the list as the attributes of @tree_column.
1375  * The attributes should be in attribute/column order, as in
1376  * gtk_tree_view_column_add_attribute(). All existing attributes
1377  * are removed, and replaced with the new attributes.
1378  **/
1379 void
1380 gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column,
1381                                      GtkCellRenderer   *cell_renderer,
1382                                      ...)
1383 {
1384   va_list args;
1385
1386   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1387   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1388   g_return_if_fail (gtk_tree_view_column_get_cell_info (tree_column, cell_renderer));
1389
1390   va_start (args, cell_renderer);
1391   gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args);
1392   va_end (args);
1393 }
1394
1395
1396 /**
1397  * gtk_tree_view_column_set_cell_data_func:
1398  * @tree_column: A #GtkTreeViewColumn
1399  * @cell_renderer: A #GtkCellRenderer
1400  * @func: The #GtkTreeViewColumnFunc to use. 
1401  * @func_data: The user data for @func.
1402  * @destroy: The destroy notification for @func_data
1403  * 
1404  * Sets the #GtkTreeViewColumnFunc to use for the column.  This
1405  * function is used instead of the standard attributes mapping for
1406  * setting the column value, and should set the value of @tree_column's
1407  * cell renderer as appropriate.  @func may be %NULL to remove an
1408  * older one.
1409  **/
1410 void
1411 gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn   *tree_column,
1412                                          GtkCellRenderer     *cell_renderer,
1413                                          GtkTreeCellDataFunc  func,
1414                                          gpointer             func_data,
1415                                          GtkDestroyNotify     destroy)
1416 {
1417   GtkTreeViewColumnCellInfo *info;
1418
1419   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1420   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1421   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1422
1423   g_return_if_fail (info != NULL);
1424
1425   if (info->destroy)
1426     {
1427       GtkDestroyNotify d = info->destroy;
1428
1429       info->destroy = NULL;
1430       d (info->func_data);
1431     }
1432
1433   info->func = func;
1434   info->func_data = func_data;
1435   info->destroy = destroy;
1436
1437   if (tree_column->tree_view)
1438     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1439 }
1440
1441
1442 /**
1443  * gtk_tree_view_column_clear_attributes:
1444  * @tree_column: a #GtkTreeViewColumn
1445  * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1446  * 
1447  * Clears all existing attributes previously set with
1448  * gtk_tree_view_column_set_attributes().
1449  **/
1450 void
1451 gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
1452                                        GtkCellRenderer   *cell_renderer)
1453 {
1454   GtkTreeViewColumnCellInfo *info;
1455   GSList *list;
1456
1457   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1458   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1459   info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1460
1461   list = info->attributes;
1462
1463   while (list && list->next)
1464     {
1465       g_free (list->data);
1466       list = list->next->next;
1467     }
1468   g_slist_free (info->attributes);
1469   info->attributes = NULL;
1470
1471   if (tree_column->tree_view)
1472     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1473 }
1474
1475
1476 /**
1477  * gtk_tree_view_column_set_spacing:
1478  * @tree_column: A #GtkTreeViewColumn.
1479  * @spacing: distance between cell renderers in pixels.
1480  * 
1481  * Sets the spacing field of @tree_column, which is the number of pixels to
1482  * place between cell renderers packed into it.
1483  **/
1484 void
1485 gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
1486                                   gint               spacing)
1487 {
1488   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1489   g_return_if_fail (spacing >= 0);
1490
1491   if (tree_column->spacing == spacing)
1492     return;
1493
1494   tree_column->spacing = spacing;
1495   if (tree_column->tree_view)
1496     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1497 }
1498
1499 /**
1500  * gtk_tree_view_column_get_spacing:
1501  * @tree_column: A #GtkTreeViewColumn.
1502  * 
1503  * Returns the spacing of @tree_column.
1504  * 
1505  * Return value: the spacing of @tree_column.
1506  **/
1507 gint
1508 gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column)
1509 {
1510   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1511
1512   return tree_column->spacing;
1513 }
1514
1515 /* Options for manipulating the columns */
1516
1517 /**
1518  * gtk_tree_view_column_set_visible:
1519  * @tree_column: A #GtkTreeViewColumn.
1520  * @visible: %TRUE if the @tree_column is visible.
1521  * 
1522  * Sets the visibility of @tree_column.
1523  **/
1524 void
1525 gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
1526                                   gboolean           visible)
1527 {
1528   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1529
1530   visible = !! visible;
1531   
1532   if (tree_column->visible == visible)
1533     return;
1534
1535   tree_column->visible = visible;
1536
1537   if (tree_column->visible)
1538     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1539
1540   gtk_tree_view_column_update_button (tree_column);
1541   g_object_notify (G_OBJECT (tree_column), "visible");
1542 }
1543
1544 /**
1545  * gtk_tree_view_column_get_visible:
1546  * @tree_column: A #GtkTreeViewColumn.
1547  * 
1548  * Returns %TRUE if @tree_column is visible.
1549  * 
1550  * Return value: whether the column is visible or not.  If it is visible, then
1551  * the tree will show the column.
1552  **/
1553 gboolean
1554 gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
1555 {
1556   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1557
1558   return tree_column->visible;
1559 }
1560
1561 /**
1562  * gtk_tree_view_column_set_resizable:
1563  * @tree_column: A #GtkTreeViewColumn
1564  * @resizable: %TRUE, if the column can be resized
1565  * 
1566  * If @resizable is %TRUE, then the user can explicitly resize the column by
1567  * grabbing the outer edge of the column button.  If resizable is TRUE and
1568  * sizing mode of the column is #GTK_TREE_VIEW_COLUMN_AUTOSIZE, then the sizing
1569  * mode is changed to #GTK_TREE_VIEW_COLUMN_GROW_ONLY.
1570  **/
1571 void
1572 gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
1573                                     gboolean           resizable)
1574 {
1575   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1576
1577   resizable = !! resizable;
1578
1579   if (tree_column->resizable == resizable)
1580     return;
1581
1582   tree_column->resizable = resizable;
1583
1584   if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1585     gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1586
1587   gtk_tree_view_column_update_button (tree_column);
1588
1589   g_object_notify (G_OBJECT (tree_column), "resizable");
1590 }
1591
1592 /**
1593  * gtk_tree_view_column_get_resizable:
1594  * @tree_column: A #GtkTreeViewColumn
1595  * 
1596  * Returns #TRUE if the @tree_column can be resized by the end user.
1597  * 
1598  * Return value: #TRUE, if the @tree_column can be resized.
1599  **/
1600 gboolean
1601 gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column)
1602 {
1603   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1604
1605   return tree_column->resizable;
1606 }
1607
1608
1609 /**
1610  * gtk_tree_view_column_set_sizing:
1611  * @tree_column: A #GtkTreeViewColumn.
1612  * @type: The #GtkTreeViewColumnSizing.
1613  * 
1614  * Sets the growth behavior of @tree_column to @type.
1615  **/
1616 void
1617 gtk_tree_view_column_set_sizing (GtkTreeViewColumn       *tree_column,
1618                                  GtkTreeViewColumnSizing  type)
1619 {
1620   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1621
1622   if (type == tree_column->column_type)
1623     return;
1624
1625   if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1626     gtk_tree_view_column_set_resizable (tree_column, FALSE);
1627
1628 #if 0
1629   /* I was clearly on crack when I wrote this.  I'm not sure what's supposed to
1630    * be below so I'll leave it until I figure it out.
1631    */
1632   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE &&
1633       tree_column->requested_width != -1)
1634     {
1635       gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width);
1636     }
1637 #endif
1638   tree_column->column_type = type;
1639
1640   gtk_tree_view_column_update_button (tree_column);
1641
1642   g_object_notify (G_OBJECT (tree_column), "sizing");
1643 }
1644
1645 /**
1646  * gtk_tree_view_column_get_sizing:
1647  * @tree_column: A #GtkTreeViewColumn.
1648  * 
1649  * Returns the current type of @tree_column.
1650  * 
1651  * Return value: The type of @tree_column.
1652  **/
1653 GtkTreeViewColumnSizing
1654 gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column)
1655 {
1656   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1657
1658   return tree_column->column_type;
1659 }
1660
1661 /**
1662  * gtk_tree_view_column_get_width:
1663  * @tree_column: A #GtkTreeViewColumn.
1664  * 
1665  * Returns the current size of @tree_column in pixels.
1666  * 
1667  * Return value: The current width of @tree_column.
1668  **/
1669 gint
1670 gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column)
1671 {
1672   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1673
1674   return tree_column->width;
1675 }
1676
1677 /**
1678  * gtk_tree_view_column_set_fixed_width:
1679  * @tree_column: A #GtkTreeViewColumn.
1680  * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1681  * 
1682  * Sets the size of the column in pixels.  This is meaningful only if the sizing
1683  * type is #GTK_TREE_VIEW_COLUMN_FIXED.  The size of the column is clamped to
1684  * the min/max width for the column.  Please note that the min/max width of the
1685  * column doesn't actually affect the "fixed_width" property of the widget, just
1686  * the actual size when displayed.
1687  **/
1688 void
1689 gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
1690                                       gint               fixed_width)
1691 {
1692   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1693   g_return_if_fail (fixed_width > 0);
1694
1695   tree_column->fixed_width = fixed_width;
1696
1697   if (tree_column->tree_view &&
1698       GTK_WIDGET_REALIZED (tree_column->tree_view) &&
1699       tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1700     {
1701       gtk_widget_queue_resize (tree_column->tree_view);
1702     }
1703
1704   g_object_notify (G_OBJECT (tree_column), "fixed_width");
1705 }
1706
1707 /**
1708  * gtk_tree_view_column_get_fixed_width:
1709  * @tree_column: a #GtkTreeViewColumn
1710  * 
1711  * Gets the fixed width of the column.  This value is only meaning may not be
1712  * the actual width of the column on the screen, just what is requested.
1713  * 
1714  * Return value: the fixed width of the column
1715  **/
1716 gint
1717 gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column)
1718 {
1719   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1720
1721   return tree_column->fixed_width;
1722 }
1723
1724 /**
1725  * gtk_tree_view_column_set_min_width:
1726  * @tree_column: A #GtkTreeViewColumn.
1727  * @min_width: The minimum width of the column in pixels, or -1.
1728  * 
1729  * Sets the minimum width of the @tree_column.  If @min_width is -1, then the
1730  * minimum width is unset.
1731  **/
1732 void
1733 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
1734                                     gint               min_width)
1735 {
1736   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1737   g_return_if_fail (min_width >= -1);
1738
1739   if (min_width == tree_column->min_width)
1740     return;
1741
1742   if (tree_column->visible &&
1743       tree_column->tree_view != NULL &&
1744       GTK_WIDGET_REALIZED (tree_column->tree_view))
1745     {
1746       if (min_width > tree_column->width)
1747         gtk_widget_queue_resize (tree_column->tree_view);
1748     }
1749
1750   tree_column->min_width = min_width;
1751   g_object_freeze_notify (G_OBJECT (tree_column));
1752   if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1753     {
1754       tree_column->max_width = min_width;
1755       g_object_notify (G_OBJECT (tree_column), "max_width");
1756     }
1757   g_object_notify (G_OBJECT (tree_column), "min_width");
1758   g_object_thaw_notify (G_OBJECT (tree_column));
1759
1760   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1761     _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view),
1762                                     tree_column);
1763 }
1764
1765 /**
1766  * gtk_tree_view_column_get_min_width:
1767  * @tree_column: A #GtkTreeViewColumn.
1768  * 
1769  * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1770  * width is set.
1771  * 
1772  * Return value: The minimum width of the @tree_column.
1773  **/
1774 gint
1775 gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
1776 {
1777   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1778
1779   return tree_column->min_width;
1780 }
1781
1782 /**
1783  * gtk_tree_view_column_set_max_width:
1784  * @tree_column: A #GtkTreeViewColumn.
1785  * @max_width: The maximum width of the column in pixels, or -1.
1786  * 
1787  * Sets the maximum width of the @tree_column.  If @max_width is -1, then the
1788  * maximum width is unset.  Note, the column can actually be wider than max
1789  * width if it's the last column in a view.  In this case, the column expands to
1790  * fill any extra space.
1791  **/
1792 void
1793 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
1794                                     gint               max_width)
1795 {
1796   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1797   g_return_if_fail (max_width >= -1);
1798
1799   if (max_width == tree_column->max_width)
1800     return;
1801
1802   if (tree_column->visible &&
1803       tree_column->tree_view != NULL &&
1804       GTK_WIDGET_REALIZED (tree_column->tree_view))
1805     {
1806       if (max_width != -1 && max_width < tree_column->width)
1807         gtk_widget_queue_resize (tree_column->tree_view);
1808     }
1809
1810   tree_column->max_width = max_width;
1811   g_object_freeze_notify (G_OBJECT (tree_column));
1812   if (max_width != -1 && max_width < tree_column->min_width)
1813     {
1814       tree_column->min_width = max_width;
1815       g_object_notify (G_OBJECT (tree_column), "min_width");
1816     }
1817   g_object_notify (G_OBJECT (tree_column), "max_width");
1818   g_object_thaw_notify (G_OBJECT (tree_column));
1819
1820   if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1821     _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view),
1822                                     tree_column);
1823 }
1824
1825 /**
1826  * gtk_tree_view_column_get_max_width:
1827  * @tree_column: A #GtkTreeViewColumn.
1828  * 
1829  * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
1830  * width is set.
1831  * 
1832  * Return value: The maximum width of the @tree_column.
1833  **/
1834 gint
1835 gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
1836 {
1837   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1838
1839   return tree_column->max_width;
1840 }
1841
1842 /**
1843  * gtk_tree_view_column_clicked:
1844  * @tree_column: a #GtkTreeViewColumn
1845  * 
1846  * Emits the "clicked" signal on the column.  This function will only work if
1847  * @tree_column is clickable.
1848  **/
1849 void
1850 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
1851 {
1852   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1853
1854   if (tree_column->visible &&
1855       tree_column->button &&
1856       tree_column->clickable)
1857     gtk_button_clicked (GTK_BUTTON (tree_column->button));
1858 }
1859
1860 /**
1861  * gtk_tree_view_column_set_title:
1862  * @tree_column: A #GtkTreeViewColumn.
1863  * @title: The title of the @tree_column.
1864  * 
1865  * Sets the title of the @tree_column.  If a custom widget has been set, then
1866  * this value is ignored.
1867  **/
1868 void
1869 gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column,
1870                                 const gchar       *title)
1871 {
1872   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1873
1874   g_free (tree_column->title);
1875   if (title)
1876     tree_column->title = g_strdup (title);
1877   else
1878     tree_column->title = NULL;
1879
1880   gtk_tree_view_column_update_button (tree_column);
1881   g_object_notify (G_OBJECT (tree_column), "title");
1882 }
1883
1884 /**
1885  * gtk_tree_view_column_get_title:
1886  * @tree_column: A #GtkTreeViewColumn.
1887  * 
1888  * Returns the title of the widget.  This value should not be modified.
1889  * 
1890  * Return value: the title of the column.
1891  **/
1892 G_CONST_RETURN gchar *
1893 gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column)
1894 {
1895   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1896
1897   return tree_column->title;
1898 }
1899
1900 /**
1901  * gtk_tree_view_column_set_clickable:
1902  * @tree_column: A #GtkTreeViewColumn.
1903  * @clickable: %TRUE if the header is active.
1904  * 
1905  * Sets the header to be active if @active is %TRUE.  When the header is active,
1906  * then it can take keyboard focus, and can be clicked.
1907  **/
1908 void
1909 gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
1910                                     gboolean           clickable)
1911 {
1912   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1913
1914   clickable = !! clickable;
1915   if (tree_column->clickable == clickable)
1916     return;
1917
1918   tree_column->clickable = clickable;
1919   gtk_tree_view_column_update_button (tree_column);
1920   g_object_notify (G_OBJECT (tree_column), "clickable");
1921 }
1922
1923 /**
1924  * gtk_tree_view_column_get_clickable:
1925  * @tree_column: a #GtkTreeViewColumn
1926  * 
1927  * Returns %TRUE if the user can click on the header for the column.
1928  * 
1929  * Return value: %TRUE if user can click the column header.
1930  **/
1931 gboolean
1932 gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
1933 {
1934   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1935
1936   return tree_column->clickable;
1937 }
1938
1939 /**
1940  * gtk_tree_view_column_set_widget:
1941  * @tree_column: A #GtkTreeViewColumn.
1942  * @widget: A child #GtkWidget, or %NULL.
1943  * 
1944  * Sets the widget in the header to be @widget.  If widget is %NULL, then the
1945  * header button is set with a #GtkLabel set to the title of @tree_column.
1946  **/
1947 void
1948 gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column,
1949                                  GtkWidget         *widget)
1950 {
1951   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1952   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
1953
1954   if (widget)
1955     {
1956       gtk_object_ref (GTK_OBJECT (widget));
1957       gtk_object_sink (GTK_OBJECT (widget));
1958     }
1959
1960   if (tree_column->child)      
1961     gtk_object_unref (GTK_OBJECT (tree_column->child));
1962
1963   tree_column->child = widget;
1964   gtk_tree_view_column_update_button (tree_column);
1965   g_object_notify (G_OBJECT (tree_column), "widget");
1966 }
1967
1968 /**
1969  * gtk_tree_view_column_get_widget:
1970  * @tree_column: A #GtkTreeViewColumn.
1971  * 
1972  * Returns the #GtkWidget in the button on the column header.  If a custom
1973  * widget has not been set then %NULL is returned.
1974  * 
1975  * Return value: The #GtkWidget in the column header, or %NULL
1976  **/
1977 GtkWidget *
1978 gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column)
1979 {
1980   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1981
1982   return tree_column->child;
1983 }
1984
1985 /**
1986  * gtk_tree_view_column_set_alignment:
1987  * @tree_column: A #GtkTreeViewColumn.
1988  * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
1989  * 
1990  * Sets the alignment of the title or custom widget inside the column header.
1991  * The alignment determines its location inside the button -- 0.0 for left, 0.5
1992  * for center, 1.0 for right.
1993  **/
1994 void
1995 gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
1996                                     gfloat             xalign)
1997 {
1998   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1999
2000   xalign = CLAMP (xalign, 0.0, 1.0);
2001
2002   if (tree_column->xalign == xalign)
2003     return;
2004
2005   tree_column->xalign = xalign;
2006   gtk_tree_view_column_update_button (tree_column);
2007   g_object_notify (G_OBJECT (tree_column), "alignment");
2008 }
2009
2010 /**
2011  * gtk_tree_view_column_get_alignment:
2012  * @tree_column: A #GtkTreeViewColumn.
2013  * 
2014  * Returns the current x alignment of @tree_column.  This value can range
2015  * between 0.0 and 1.0.
2016  * 
2017  * Return value: The current alignent of @tree_column.
2018  **/
2019 gfloat
2020 gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
2021 {
2022   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0.5);
2023
2024   return tree_column->xalign;
2025 }
2026
2027 /**
2028  * gtk_tree_view_column_set_reorderable:
2029  * @tree_column: A #GtkTreeViewColumn
2030  * @reorderable: #TRUE, if the column can be reordered.
2031  * 
2032  * If @reorderable is #TRUE, then the column can be reordered by the end user
2033  * dragging the header.
2034  **/
2035 void
2036 gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column,
2037                                       gboolean           reorderable)
2038 {
2039   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2040
2041   /*  if (reorderable)
2042       gtk_tree_view_column_set_clickable (tree_column, TRUE);*/
2043
2044   if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2045     return;
2046
2047   tree_column->reorderable = (reorderable?TRUE:FALSE);
2048   gtk_tree_view_column_update_button (tree_column);
2049   g_object_notify (G_OBJECT (tree_column), "reorderable");
2050 }
2051
2052 /**
2053  * gtk_tree_view_column_get_reorderable:
2054  * @tree_column: A #GtkTreeViewColumn
2055  * 
2056  * Returns #TRUE if the @tree_column can be reordered by the user.
2057  * 
2058  * Return value: #TRUE if the @tree_column can be reordered by the user.
2059  **/
2060 gboolean
2061 gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column)
2062 {
2063   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2064
2065   return tree_column->reorderable;
2066 }
2067
2068
2069 /**
2070  * gtk_tree_view_column_set_sort_column_id:
2071  * @tree_column: a #GtkTreeViewColumn
2072  * @sort_column_id: The @sort_column_id of the model to sort on.
2073  * 
2074  * Sets the logical @sort_column_id that this column sorts on when this column 
2075  * is selected for sorting.  Doing so makes the column header clickable.
2076  **/
2077 void
2078 gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
2079                                          gint               sort_column_id)
2080 {
2081   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2082   g_return_if_fail (sort_column_id >= 0);
2083
2084   if (tree_column->sort_column_id == sort_column_id)
2085     return;
2086
2087   tree_column->sort_column_id = sort_column_id;
2088
2089   /* Handle unsetting the id */
2090   if (sort_column_id == -1)
2091     {
2092       if (tree_column->sort_clicked_signal)
2093         {
2094           g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_clicked_signal);
2095           tree_column->sort_clicked_signal = 0;
2096         }
2097
2098       if (tree_column->sort_column_changed_signal)
2099         {
2100           g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_column_changed_signal);
2101           tree_column->sort_column_changed_signal = 0;
2102         }
2103
2104       gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2105       gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
2106       return;
2107     }
2108
2109   gtk_tree_view_column_set_clickable (tree_column, TRUE);
2110
2111   if (! tree_column->sort_clicked_signal)
2112     tree_column->sort_clicked_signal = g_signal_connect (G_OBJECT (tree_column),
2113                                                          "clicked",
2114                                                          G_CALLBACK (gtk_tree_view_column_sort),
2115                                                          NULL);
2116
2117   gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
2118 }
2119
2120 /**
2121  * gtk_tree_view_column_get_sort_column_id:
2122  * @tree_column: a #GtkTreeViewColumn
2123  *
2124  * Gets the logical @sort_column_id that the model sorts on when this
2125  * column is selected for sorting. See gtk_tree_view_column_set_sort_column_id().
2126  *
2127  * Return value: the current @sort_column_id for this column, or -1 if
2128  *               this column can't be used for sorting.
2129  **/
2130 gint
2131 gtk_tree_view_column_get_sort_column_id (GtkTreeViewColumn *tree_column)
2132 {
2133   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2134
2135   return tree_column->sort_column_id;
2136 }
2137
2138 /**
2139  * gtk_tree_view_column_set_sort_indicator:
2140  * @tree_column: a #GtkTreeViewColumn
2141  * @setting: %TRUE to display an indicator that the column is sorted
2142  *
2143  * Call this function with a @setting of %TRUE to display an arrow in
2144  * the header button indicating the column is sorted. Call
2145  * gtk_tree_view_column_set_sort_order() to change the direction of
2146  * the arrow.
2147  * 
2148  **/
2149 void
2150 gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn     *tree_column,
2151                                          gboolean               setting)
2152 {
2153   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2154
2155   setting = setting != FALSE;
2156
2157   if (setting == tree_column->show_sort_indicator)
2158     return;
2159
2160   tree_column->show_sort_indicator = setting;
2161   gtk_tree_view_column_update_button (tree_column);
2162   g_object_notify (G_OBJECT (tree_column), "sort_indicator");
2163 }
2164
2165 /**
2166  * gtk_tree_view_column_get_sort_indicator:
2167  * @tree_column: a #GtkTreeViewColumn
2168  * 
2169  * Gets the value set by gtk_tree_view_column_set_sort_indicator().
2170  * 
2171  * Return value: whether the sort indicator arrow is displayed
2172  **/
2173 gboolean
2174 gtk_tree_view_column_get_sort_indicator  (GtkTreeViewColumn     *tree_column)
2175 {
2176   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2177
2178   return tree_column->show_sort_indicator;
2179 }
2180
2181 /**
2182  * gtk_tree_view_column_set_sort_order:
2183  * @tree_column: a #GtkTreeViewColumn
2184  * @order: sort order that the sort indicator should indicate
2185  *
2186  * Changes the appearance of the sort indicator. 
2187  * 
2188  * This <emphasis>does not</emphasis> actually sort the model.  Use
2189  * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
2190  * support.  This function is primarily for custom sorting behavior, and should
2191  * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2192  * that. For custom models, the mechanism will vary. 
2193  * 
2194  * The sort indicator changes direction to indicate normal sort or reverse sort.
2195  * Note that you must have the sort indicator enabled to see anything when 
2196  * calling this function; see gtk_tree_view_column_set_sort_indicator().
2197  **/
2198 void
2199 gtk_tree_view_column_set_sort_order      (GtkTreeViewColumn     *tree_column,
2200                                           GtkSortType            order)
2201 {
2202   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2203
2204   if (order == tree_column->sort_order)
2205     return;
2206
2207   tree_column->sort_order = order;
2208   gtk_tree_view_column_update_button (tree_column);
2209   g_object_notify (G_OBJECT (tree_column), "sort_order");
2210 }
2211
2212 /**
2213  * gtk_tree_view_column_get_sort_order:
2214  * @tree_column: a #GtkTreeViewColumn
2215  * 
2216  * Gets the value set by gtk_tree_view_column_set_sort_order().
2217  * 
2218  * Return value: the sort order the sort indicator is indicating
2219  **/
2220 GtkSortType
2221 gtk_tree_view_column_get_sort_order      (GtkTreeViewColumn     *tree_column)
2222 {
2223   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2224
2225   return tree_column->sort_order;
2226 }
2227
2228 /**
2229  * gtk_tree_view_column_cell_set_cell_data:
2230  * @tree_column: A #GtkTreeViewColumn.
2231  * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2232  * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2233  * @is_expander: %TRUE, if the row has children
2234  * @is_expanded: %TRUE, if the row has visible children
2235  * 
2236  * Sets the cell renderer based on the @tree_model and @tree_node.  That is, for
2237  * every attribute mapping in @tree_column, it will get a value from the set
2238  * column on the @tree_node, and use that value to set the attribute on the cell
2239  * renderer.  This is used primarily by the #GtkTreeView.
2240  **/
2241 void
2242 gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column,
2243                                          GtkTreeModel      *tree_model,
2244                                          GtkTreeIter       *iter,
2245                                          gboolean           is_expander,
2246                                          gboolean           is_expanded)
2247 {
2248   GSList *list;
2249   GValue value = { 0, };
2250   GList *cell_list;
2251
2252   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2253   g_return_if_fail (tree_column->cell_list != NULL);
2254
2255   if (tree_model == NULL)
2256     return;
2257
2258   for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2259     {
2260       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data;
2261       GObject *cell = (GObject *) info->cell;
2262
2263       list = info->attributes;
2264
2265       g_object_freeze_notify (cell);
2266       g_object_set (cell, "is_expander", is_expander, "is_expanded", is_expanded, NULL);
2267
2268       while (list && list->next)
2269         {
2270           gtk_tree_model_get_value (tree_model, iter,
2271                                     GPOINTER_TO_INT (list->next->data),
2272                                     &value);
2273           g_object_set_property (cell, (gchar *) list->data, &value);
2274           g_value_unset (&value);
2275           list = list->next->next;
2276         }
2277
2278       if (info->func)
2279         (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2280       g_object_thaw_notify (G_OBJECT (info->cell));
2281     }
2282
2283 }
2284
2285 /**
2286  * gtk_tree_view_column_cell_get_size:
2287  * @tree_column: A #GtkTreeViewColumn.
2288  * @cell_area: The area a the column will be allocated, or %NULL
2289  * @x_offset: location to return x offset of cell relative to @cell_area, or %NULL
2290  * @y_offset: location to return y offset of cell relative to @cell_area, or %NULL
2291  * @width: location to return width needed to render a cell, or %NULL
2292  * @height: location to return height needed to render a cell, or %NULL
2293  * 
2294  * Obtains the width and height needed to render the column.  This is used
2295  * primarily by the #GtkTreeView.
2296  **/
2297 void
2298 gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
2299                                     GdkRectangle      *cell_area,
2300                                     gint              *x_offset,
2301                                     gint              *y_offset,
2302                                     gint              *width,
2303                                     gint              *height)
2304 {
2305   GList *list;
2306   gboolean first_cell = TRUE;
2307   gint focus_line_width;
2308
2309   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2310
2311   if (height)
2312     * height = 0;
2313   if (width)
2314     * width = 0;
2315
2316   gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2317   
2318   for (list = tree_column->cell_list; list; list = list->next)
2319     {
2320       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2321       gboolean visible;
2322       gint new_height = 0;
2323       gint new_width = 0;
2324       g_object_get (info->cell, "visible", &visible, NULL);
2325
2326       if (visible == FALSE)
2327         continue;
2328
2329       if (first_cell == FALSE && *width)
2330         *width += tree_column->spacing;
2331
2332       gtk_cell_renderer_get_size (info->cell,
2333                                   tree_column->tree_view,
2334                                   cell_area,
2335                                   x_offset,
2336                                   y_offset,
2337                                   &new_width,
2338                                   &new_height);
2339
2340       if (height)
2341         * height = MAX (*height, new_height + focus_line_width * 2);
2342       info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2343       if (width)
2344         * width += info->requested_width;
2345       first_cell = FALSE;
2346     }
2347 }
2348
2349 /* both rendering and rendering focus are somewhat complicated, and a bit of
2350  * code.  Rather than duplicate them, we put them together to keep the code in
2351  * one place
2352  */
2353 enum {
2354   CELL_ACTION_RENDER,
2355   CELL_ACTION_FOCUS,
2356   CELL_ACTION_EVENT
2357 };
2358
2359 static gboolean
2360 gtk_tree_view_column_cell_process_action (GtkTreeViewColumn  *tree_column,
2361                                           GdkWindow          *window,
2362                                           GdkRectangle       *background_area,
2363                                           GdkRectangle       *cell_area,
2364                                           guint               flags,
2365                                           gint                action,
2366                                           GdkRectangle       *expose_area,     /* RENDER */
2367                                           GdkRectangle       *focus_rectangle, /* FOCUS  */
2368                                           GtkCellEditable   **editable_widget, /* EVENT  */
2369                                           GdkEvent           *event,           /* EVENT  */
2370                                           gchar              *path_string)     /* EVENT  */
2371 {
2372   GList *list;
2373   GdkRectangle real_cell_area;
2374   GdkRectangle real_background_area;
2375   gint expand_cell_count = 0;
2376   gint full_requested_width = 0;
2377   gint extra_space;
2378   gint min_x, min_y, max_x, max_y;
2379   gint focus_line_width;
2380   gint dx;
2381   gint special_cells;
2382
2383   min_x = G_MAXINT;
2384   min_y = G_MAXINT;
2385   max_x = 0;
2386   max_y = 0;
2387
2388   special_cells = _gtk_tree_view_column_count_special_cells (tree_column);
2389
2390   if (special_cells > 1 && action == CELL_ACTION_FOCUS)
2391     {
2392       GtkTreeViewColumnCellInfo *info = NULL;
2393       gboolean found_has_focus = FALSE;
2394
2395       /* one should have focus */
2396       for (list = tree_column->cell_list; list; list = list->next)
2397         {
2398           info = list->data;
2399           if (info && info->has_focus)
2400             {
2401               found_has_focus = TRUE;
2402               break;
2403             }
2404         }
2405
2406       if (!found_has_focus)
2407         {
2408           /* give the first one focus */
2409           info = gtk_tree_view_column_cell_first (tree_column)->data;
2410           info->has_focus = TRUE;
2411         }
2412     }
2413
2414   gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2415                         "focus-line-width", &focus_line_width,
2416                         NULL);
2417
2418   real_cell_area = *cell_area;
2419   real_background_area = *background_area;
2420   dx = real_cell_area.x - real_background_area.x - focus_line_width;
2421
2422   real_cell_area.x += focus_line_width;
2423
2424   /* Find out how many extra space we have to allocate */
2425   for (list = tree_column->cell_list; list; list = list->next)
2426     {
2427       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
2428
2429       if (! info->cell->visible)
2430         continue;
2431
2432       if (info->expand == TRUE)
2433         expand_cell_count ++;
2434       full_requested_width += info->requested_width;
2435     }
2436
2437   extra_space = background_area->width - full_requested_width;
2438   if (extra_space < 0)
2439     extra_space = 0;
2440   else if (extra_space > 0 && expand_cell_count > 0)
2441     extra_space /= expand_cell_count;
2442
2443   /* iterate list for GTK_PACK_START cells */
2444   for (list = tree_column->cell_list; list; list = list->next)
2445     {
2446       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2447
2448       if (info->pack == GTK_PACK_END)
2449         continue;
2450
2451       if (! info->cell->visible)
2452         continue;
2453
2454       real_background_area.width = info->requested_width +
2455         (info->expand?extra_space:0);
2456       info->real_width = real_background_area.width;
2457
2458       real_cell_area.width = real_background_area.width;
2459       real_cell_area.width -= 2 * focus_line_width;
2460
2461       if (action == CELL_ACTION_RENDER)
2462         {
2463           gtk_cell_renderer_render (info->cell,
2464                                     window,
2465                                     tree_column->tree_view,
2466                                     &real_background_area,
2467                                     &real_cell_area,
2468                                     expose_area,
2469                                     flags);
2470         }
2471       else if (action == CELL_ACTION_FOCUS)
2472         {
2473           gint x_offset, y_offset, width, height;
2474
2475           gtk_cell_renderer_get_size (info->cell,
2476                                       tree_column->tree_view,
2477                                       &real_cell_area,
2478                                       &x_offset, &y_offset,
2479                                       &width, &height);
2480
2481           if (special_cells > 1)
2482             {
2483               if (info->has_focus)
2484                 {
2485                   min_x = real_cell_area.x + x_offset;
2486                   max_x = min_x + width;
2487                   min_y = real_cell_area.y + y_offset;
2488                   max_y = min_y + height;
2489                 }
2490             }
2491           else
2492             {
2493               if (min_x > (real_cell_area.x + x_offset))
2494                 min_x = real_cell_area.x + x_offset;
2495               if (max_x < real_cell_area.x + x_offset + width)
2496                 max_x = real_cell_area.x + x_offset + width;
2497               if (min_y > (real_cell_area.y + y_offset))
2498                 min_y = real_cell_area.y + y_offset;
2499               if (max_y < real_cell_area.y + y_offset + height)
2500                 max_y = real_cell_area.y + y_offset + height;
2501             }
2502         }
2503       else if (action == CELL_ACTION_EVENT)
2504         {
2505           gboolean try_event = FALSE;
2506
2507           if (event)
2508             {
2509               if (special_cells == 1)
2510                 {
2511                   /* only 1 activatable cell -> whole column can activate */
2512                   if (cell_area->x <= ((GdkEventButton *)event)->x &&
2513                       cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2514                     try_event = TRUE;
2515                 }
2516               else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
2517                   real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
2518                   /* only activate cell if the user clicked on an individual
2519                    * cell
2520                    */
2521                 try_event = TRUE;
2522             }
2523           else if (special_cells > 1 && info->has_focus)
2524             try_event = TRUE;
2525           else if (special_cells == 1)
2526             try_event = TRUE;
2527
2528           if (try_event)
2529             {
2530               gboolean visible, mode;
2531
2532               g_object_get (G_OBJECT (info->cell),
2533                             "visible", &visible,
2534                             "mode", &mode,
2535                             NULL);
2536               if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2537                 {
2538                   if (gtk_cell_renderer_activate (info->cell,
2539                                                   event,
2540                                                   tree_column->tree_view,
2541                                                   path_string,
2542                                                   background_area,
2543                                                   cell_area,
2544                                                   flags))
2545                     return TRUE;
2546                 }
2547               else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2548                 {
2549                   *editable_widget =
2550                     gtk_cell_renderer_start_editing (info->cell,
2551                                                      event,
2552                                                      tree_column->tree_view,
2553                                                      path_string,
2554                                                      background_area,
2555                                                      cell_area,
2556                                                      flags);
2557
2558                   if (*editable_widget != NULL)
2559                     {
2560                       g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2561                       info->in_editing_mode = TRUE;
2562                       gtk_tree_view_column_focus_cell (tree_column, info->cell);
2563                       
2564                       return TRUE;
2565                     }
2566                 }
2567             }
2568         }
2569
2570       real_cell_area.x += (info->real_width + tree_column->spacing);
2571       real_background_area.x += (info->real_width + tree_column->spacing);
2572     }
2573
2574   /* iterate list for PACK_END cells */
2575   for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2576     {
2577       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2578
2579       if (info->pack == GTK_PACK_START)
2580         continue;
2581
2582       if (! info->cell->visible)
2583         continue;
2584
2585       real_background_area.width = info->requested_width +
2586         (info->expand?extra_space:0);
2587       info->real_width = real_background_area.width;
2588
2589       real_cell_area.width = real_background_area.width;
2590       real_cell_area.width -= 2 * focus_line_width;
2591
2592       if (action == CELL_ACTION_RENDER)
2593         {
2594           gtk_cell_renderer_render (info->cell,
2595                                     window,
2596                                     tree_column->tree_view,
2597                                     &real_background_area,
2598                                     &real_cell_area,
2599                                     expose_area,
2600                                     flags);
2601         }
2602       else if (action == CELL_ACTION_FOCUS)
2603         {
2604           gint x_offset, y_offset, width, height;
2605
2606           gtk_cell_renderer_get_size (info->cell,
2607                                       tree_column->tree_view,
2608                                       &real_cell_area,
2609                                       &x_offset, &y_offset,
2610                                       &width, &height);
2611
2612           if (special_cells > 1)
2613             {
2614               if (info->has_focus)
2615                 {
2616                   min_x = real_cell_area.x + x_offset;
2617                   max_x = min_x + width;
2618                   min_y = real_cell_area.y + y_offset;
2619                   max_y = min_y + height;
2620                 }
2621             }
2622           else
2623             {
2624               if (min_x > (real_cell_area.x + x_offset))
2625                 min_x = real_cell_area.x + x_offset;
2626               if (max_x < real_cell_area.x + x_offset + width)
2627                 max_x = real_cell_area.x + x_offset + width;
2628               if (min_y > (real_cell_area.y + y_offset))
2629                 min_y = real_cell_area.y + y_offset;
2630               if (max_y < real_cell_area.y + y_offset + height)
2631                 max_y = real_cell_area.y + y_offset + height;
2632             }
2633         }
2634       else if (action == CELL_ACTION_EVENT)
2635         {
2636           gboolean try_event = FALSE;
2637
2638           if (event)
2639             {
2640               if (special_cells == 1)
2641                 {
2642                   /* only 1 activatable cell -> whole column can activate */
2643                   if (cell_area->x <= ((GdkEventButton *)event)->x &&
2644                       cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2645                     try_event = TRUE;
2646                 }
2647               else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
2648                   real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
2649                 /* only activate cell if the user clicked on an individual
2650                  * cell
2651                  */
2652                 try_event = TRUE;
2653             }
2654           else if (special_cells > 1 && info->has_focus)
2655             try_event = TRUE;
2656           else if (special_cells == 1)
2657             try_event = TRUE;
2658
2659           if (try_event)
2660             {
2661               gboolean visible, mode;
2662
2663               g_object_get (G_OBJECT (info->cell),
2664                             "visible", &visible,
2665                             "mode", &mode,
2666                             NULL);
2667               if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2668                 {
2669                   if (gtk_cell_renderer_activate (info->cell,
2670                                                   event,
2671                                                   tree_column->tree_view,
2672                                                   path_string,
2673                                                   background_area,
2674                                                   cell_area,
2675                                                   flags))
2676                     return TRUE;
2677                 }
2678               else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2679                 {
2680                   *editable_widget =
2681                     gtk_cell_renderer_start_editing (info->cell,
2682                                                      event,
2683                                                      tree_column->tree_view,
2684                                                      path_string,
2685                                                      background_area,
2686                                                      cell_area,
2687                                                      flags);
2688
2689                   if (*editable_widget != NULL)
2690                     {
2691                       g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2692                       info->in_editing_mode = TRUE;
2693                       gtk_tree_view_column_focus_cell (tree_column, info->cell);
2694
2695                       return TRUE;
2696                     }
2697                 }
2698             }
2699         }
2700
2701       real_cell_area.x += (info->real_width + tree_column->spacing);
2702       real_background_area.x += (info->real_width + tree_column->spacing);
2703     }
2704
2705   /* fill focus_rectangle when required */
2706   if (action == CELL_ACTION_FOCUS)
2707     {
2708       if (min_x >= max_x || min_y >= max_y)
2709         {
2710           *focus_rectangle = *cell_area;
2711           /* don't change the focus_rectangle, just draw it nicely inside
2712            * the cell area */
2713         }
2714       else
2715         {
2716           focus_rectangle->x = min_x - focus_line_width;
2717           focus_rectangle->y = min_y - focus_line_width;
2718           focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
2719           focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
2720         }
2721     }
2722
2723   return FALSE;
2724 }
2725
2726 /**
2727  * gtk_tree_view_column_cell_render:
2728  * @tree_column: A #GtkTreeViewColumn.
2729  * @window: a #GdkDrawable to draw to
2730  * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
2731  * @cell_area: area normally rendered by a cell renderer
2732  * @expose_area: area that actually needs updating
2733  * @flags: flags that affect rendering
2734  * 
2735  * Renders the cell contained by #tree_column. This is used primarily by the
2736  * #GtkTreeView.
2737  **/
2738 void
2739 _gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
2740                                    GdkWindow         *window,
2741                                    GdkRectangle      *background_area,
2742                                    GdkRectangle      *cell_area,
2743                                    GdkRectangle      *expose_area,
2744                                    guint              flags)
2745 {
2746   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2747   g_return_if_fail (background_area != NULL);
2748   g_return_if_fail (cell_area != NULL);
2749   g_return_if_fail (expose_area != NULL);
2750
2751   gtk_tree_view_column_cell_process_action (tree_column,
2752                                             window,
2753                                             background_area,
2754                                             cell_area,
2755                                             flags,
2756                                             CELL_ACTION_RENDER,
2757                                             expose_area,
2758                                             NULL, NULL, NULL, NULL);
2759 }
2760
2761 gboolean
2762 _gtk_tree_view_column_cell_event (GtkTreeViewColumn  *tree_column,
2763                                   GtkCellEditable   **editable_widget,
2764                                   GdkEvent           *event,
2765                                   gchar              *path_string,
2766                                   GdkRectangle       *background_area,
2767                                   GdkRectangle       *cell_area,
2768                                   guint               flags)
2769 {
2770   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2771
2772   return gtk_tree_view_column_cell_process_action (tree_column,
2773                                                    NULL,
2774                                                    background_area,
2775                                                    cell_area,
2776                                                    flags,
2777                                                    CELL_ACTION_EVENT,
2778                                                    NULL, NULL,
2779                                                    editable_widget,
2780                                                    event,
2781                                                    path_string);
2782 }
2783
2784 /* cell list manipulation */
2785 static GList *
2786 gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column)
2787 {
2788   GList *list = tree_column->cell_list;
2789
2790   /* first GTK_PACK_START cell we find */
2791   for ( ; list; list = list->next)
2792     {
2793       GtkTreeViewColumnCellInfo *info = list->data;
2794       if (info->pack == GTK_PACK_START)
2795         return list;
2796     }
2797
2798   /* hmm, else the *last* GTK_PACK_END cell */
2799   list = g_list_last (tree_column->cell_list);
2800
2801   for ( ; list; list = list->prev)
2802     {
2803       GtkTreeViewColumnCellInfo *info = list->data;
2804       if (info->pack == GTK_PACK_END)
2805         return list;
2806     }
2807
2808   return NULL;
2809 }
2810
2811 static GList *
2812 gtk_tree_view_column_cell_last (GtkTreeViewColumn *tree_column)
2813 {
2814   GList *list = tree_column->cell_list;
2815
2816   /* *first* GTK_PACK_END cell we find */
2817   for ( ; list ; list = list->next)
2818     {
2819       GtkTreeViewColumnCellInfo *info = list->data;
2820       if (info->pack == GTK_PACK_END)
2821         return list;
2822     }
2823
2824   /* hmm, else the last GTK_PACK_START cell */
2825   list = g_list_last (tree_column->cell_list);
2826
2827   for ( ; list; list = list->prev)
2828     {
2829       GtkTreeViewColumnCellInfo *info = list->data;
2830       if (info->pack == GTK_PACK_START)
2831         return list;
2832     }
2833
2834   return NULL;
2835 }
2836
2837 static GList *
2838 gtk_tree_view_column_cell_next (GtkTreeViewColumn *tree_column,
2839                                 GList             *current)
2840 {
2841   GList *list;
2842   GtkTreeViewColumnCellInfo *info = current->data;
2843
2844   if (info->pack == GTK_PACK_START)
2845     {
2846       for (list = current->next; list; list = list->next)
2847         {
2848           GtkTreeViewColumnCellInfo *inf = list->data;
2849           if (inf->pack == GTK_PACK_START)
2850             return list;
2851         }
2852
2853       /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
2854       list = g_list_last (tree_column->cell_list);
2855       for (; list; list = list->prev)
2856         {
2857           GtkTreeViewColumnCellInfo *inf = list->data;
2858           if (inf->pack == GTK_PACK_END)
2859             return list;
2860         }
2861     }
2862
2863   for (list = current->prev; list; list = list->prev)
2864     {
2865       GtkTreeViewColumnCellInfo *inf = list->data;
2866       if (inf->pack == GTK_PACK_END)
2867         return list;
2868     }
2869
2870   return NULL;
2871 }
2872
2873 static GList *
2874 gtk_tree_view_column_cell_prev (GtkTreeViewColumn *tree_column,
2875                                 GList             *current)
2876 {
2877   GList *list;
2878   GtkTreeViewColumnCellInfo *info = current->data;
2879
2880   if (info->pack == GTK_PACK_END)
2881     {
2882       for (list = current->next; list; list = list->next)
2883         {
2884           GtkTreeViewColumnCellInfo *inf = list->data;
2885           if (inf->pack == GTK_PACK_END)
2886             return list;
2887         }
2888
2889       /* out of GTK_PACK_END, get last GTK_PACK_START one */
2890       list = g_list_last (tree_column->cell_list);
2891       for ( ; list; list = list->prev)
2892         {
2893           GtkTreeViewColumnCellInfo *inf = list->data;
2894           if (inf->pack == GTK_PACK_START)
2895             return list;
2896         }
2897     }
2898
2899   for (list = current->prev; list; list = list->prev)
2900     {
2901       GtkTreeViewColumnCellInfo *inf = list->data;
2902       if (inf->pack == GTK_PACK_START)
2903         return list;
2904     }
2905
2906   return NULL;
2907 }
2908
2909 gboolean
2910 _gtk_tree_view_column_cell_focus (GtkTreeViewColumn *tree_column,
2911                                   gint               direction,
2912                                   gboolean           left,
2913                                   gboolean           right)
2914 {
2915   gint count;
2916
2917   count = _gtk_tree_view_column_count_special_cells (tree_column);
2918
2919   /* if we are the current focus column and have multiple editable cells,
2920    * try to select the next one, else move the focus to the next column
2921    */
2922   if (GTK_TREE_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
2923     {
2924       if (count > 1)
2925         {
2926           GList *next, *prev;
2927           GList *list = tree_column->cell_list;
2928           GtkTreeViewColumnCellInfo *info = NULL;
2929
2930           /* find current focussed cell */
2931           for ( ; list; list = list->next)
2932             {
2933               info = list->data;
2934               if (info->has_focus)
2935                 break;
2936             }
2937
2938           /* not a focussed cell in the focus column? */
2939           if (!list || !info || !info->has_focus)
2940             return FALSE;
2941
2942           next = gtk_tree_view_column_cell_next (tree_column, list);
2943           prev = gtk_tree_view_column_cell_prev (tree_column, list);
2944
2945           info->has_focus = FALSE;
2946           if (direction > 0 && next)
2947             {
2948               info = next->data;
2949               info->has_focus = TRUE;
2950               return TRUE;
2951             }
2952           else if (direction > 0 && !next && !right)
2953             {
2954               /* keep focus on latest cell */
2955               info = gtk_tree_view_column_cell_last (tree_column)->data;
2956               info->has_focus = TRUE;
2957               return TRUE;
2958             }
2959           else if (direction < 0 && prev)
2960             {
2961               info = prev->data;
2962               info->has_focus = TRUE;
2963               return TRUE;
2964             }
2965           else if (direction < 0 && !prev && !left)
2966             {
2967               /* keep focus on first cell */
2968               info = gtk_tree_view_column_cell_first (tree_column)->data;
2969               info->has_focus = TRUE;
2970               return TRUE;
2971             }
2972         }
2973       return FALSE;
2974     }
2975
2976   /* we get focus, if we have multiple editable cells, give the correct one
2977    * focus
2978    */
2979   if (count > 1)
2980     {
2981       GList *list = tree_column->cell_list;
2982
2983       /* clear focus first */
2984       for ( ; list ; list = list->next)
2985         {
2986           GtkTreeViewColumnCellInfo *info = list->data;
2987           if (info->has_focus)
2988             info->has_focus = FALSE;
2989         }
2990
2991       if (direction > 0)
2992         ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_first (tree_column)->data)->has_focus = TRUE;
2993       else if (direction < 0)
2994         ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_last (tree_column)->data)->has_focus = TRUE;
2995     }
2996   return TRUE;
2997 }
2998
2999 void
3000 _gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn       *tree_column,
3001                                        GdkWindow               *window,
3002                                        GdkRectangle            *background_area,
3003                                        GdkRectangle            *cell_area,
3004                                        GdkRectangle            *expose_area,
3005                                        guint                    flags)
3006 {
3007   gint focus_line_width;
3008   GtkStateType cell_state;
3009   
3010   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
3011   gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3012                         "focus-line-width", &focus_line_width, NULL);
3013   if (tree_column->editable_widget)
3014     {
3015       /* This function is only called on the editable row when editing.
3016        */
3017 #if 0
3018       gtk_paint_focus (tree_column->tree_view->style,
3019                        window,
3020                        GTK_WIDGET_STATE (tree_column->tree_view),
3021                        NULL,
3022                        tree_column->tree_view,
3023                        "treeview",
3024                        cell_area->x - focus_line_width,
3025                        cell_area->y - focus_line_width,
3026                        cell_area->width + 2 * focus_line_width,
3027                        cell_area->height + 2 * focus_line_width);
3028 #endif      
3029     }
3030   else
3031     {
3032       GdkRectangle focus_rectangle;
3033       gtk_tree_view_column_cell_process_action (tree_column,
3034                                                 window,
3035                                                 background_area,
3036                                                 cell_area,
3037                                                 flags,
3038                                                 CELL_ACTION_FOCUS,
3039                                                 expose_area,
3040                                                 &focus_rectangle,
3041                                                 NULL, NULL, NULL);
3042
3043       cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3044               (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3045               (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3046       gtk_paint_focus (tree_column->tree_view->style,
3047                        window,
3048                        cell_state,
3049                        NULL,
3050                        tree_column->tree_view,
3051                        "treeview",
3052                        focus_rectangle.x,
3053                        focus_rectangle.y,
3054                        focus_rectangle.width,
3055                        focus_rectangle.height);
3056     }
3057 }
3058
3059 /**
3060  * gtk_tree_view_column_cell_is_visible:
3061  * @tree_column: A #GtkTreeViewColumn
3062  * 
3063  * Returns #TRUE if any of the cells packed into the @tree_column are visible.
3064  * For this to be meaningful, you must first initialize the cells with
3065  * gtk_tree_view_column_cell_set_cell_data()
3066  * 
3067  * Return value: #TRUE, if any of the cells packed into the @tree_column are currently visible
3068  **/
3069 gboolean
3070 gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
3071 {
3072   GList *list;
3073
3074   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
3075
3076   for (list = tree_column->cell_list; list; list = list->next)
3077     {
3078       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
3079
3080       if (info->cell->visible)
3081         return TRUE;
3082     }
3083
3084   return FALSE;
3085 }
3086
3087 /**
3088  * gtk_tree_view_column_focus_cell:
3089  * @tree_view: A #GtkTreeView
3090  * @cell: A #GtkCellRenderer
3091  *
3092  * Sets the current keyboard focus to be at @cell, if the column contains
3093  * 2 or more editable and activatable cells.
3094  **/
3095 void
3096 gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column,
3097                                  GtkCellRenderer   *cell)
3098 {
3099   GList *list;
3100   gboolean found_cell = FALSE;
3101
3102   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
3103   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3104
3105   if (_gtk_tree_view_column_count_special_cells (tree_column) < 2)
3106     return;
3107
3108   for (list = tree_column->cell_list; list; list = list->next)
3109     {
3110       GtkTreeViewColumnCellInfo *info = list->data;
3111
3112       if (info->cell == cell)
3113         {
3114           info->has_focus = TRUE;
3115           found_cell = TRUE;
3116           break;
3117         }
3118     }
3119
3120   if (found_cell)
3121     {
3122       for (list = tree_column->cell_list; list; list = list->next)
3123         {
3124           GtkTreeViewColumnCellInfo *info = list->data;
3125
3126           if (info->cell != cell)
3127             info->has_focus = FALSE;
3128         }
3129
3130       /* FIXME: redraw? */
3131     }
3132 }
3133
3134 void
3135 _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
3136                                       gboolean           install_handler)
3137 {
3138   GList *list;
3139
3140   for (list = tree_column->cell_list; list; list = list->next)
3141     {
3142       GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
3143
3144       info->requested_width = 0;
3145     }
3146   tree_column->dirty = TRUE;
3147   tree_column->resized_width = MAX (tree_column->requested_width, tree_column->button_request);
3148   tree_column->requested_width = -1;
3149   tree_column->width = 0;
3150
3151   if (tree_column->tree_view &&
3152       GTK_WIDGET_REALIZED (tree_column->tree_view))
3153     {
3154       if (install_handler)
3155         _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
3156       else
3157         GTK_TREE_VIEW (tree_column->tree_view)->priv->mark_rows_col_dirty = TRUE;
3158       gtk_widget_queue_resize (tree_column->tree_view);
3159     }
3160 }
3161
3162 void
3163 _gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
3164                                      GtkCellEditable   *cell_editable)
3165 {
3166   g_return_if_fail (tree_column->editable_widget == NULL);
3167
3168   tree_column->editable_widget = cell_editable;
3169 }
3170
3171 void
3172 _gtk_tree_view_column_stop_editing (GtkTreeViewColumn *tree_column)
3173 {
3174   GList *list;
3175
3176   g_return_if_fail (tree_column->editable_widget != NULL);
3177
3178   tree_column->editable_widget = NULL;
3179   for (list = tree_column->cell_list; list; list = list->next)
3180     ((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
3181 }
3182
3183 void
3184 _gtk_tree_view_column_get_neighbor_sizes (GtkTreeViewColumn *column,
3185                                           GtkCellRenderer   *cell,
3186                                           gint              *left,
3187                                           gint              *right)
3188 {
3189   GList *list;
3190
3191   if (left)
3192     {
3193       *left = 0;
3194       list = gtk_tree_view_column_cell_first (column);
3195
3196       for (; list; list = gtk_tree_view_column_cell_next (column, list))
3197         {
3198           GtkTreeViewColumnCellInfo *info =
3199             (GtkTreeViewColumnCellInfo *)list->data;
3200
3201           if (info->cell == cell)
3202             break;
3203
3204           *left += info->real_width;
3205         }
3206     }
3207
3208   if (right)
3209     {
3210       GList *next;
3211
3212       *right = 0;
3213       list = gtk_tree_view_column_cell_first (column);
3214
3215       for (; list; list = gtk_tree_view_column_cell_next (column, list))
3216         {
3217           GtkTreeViewColumnCellInfo *info =
3218             (GtkTreeViewColumnCellInfo *)list->data;
3219
3220           if (info->cell == cell)
3221             break;
3222         }
3223
3224       /* skip cell */
3225       next = gtk_tree_view_column_cell_next (column, list);
3226       if (list && next)
3227         {
3228           list = next;
3229           for ( ; list; list = gtk_tree_view_column_cell_next (column, list))
3230             {
3231               GtkTreeViewColumnCellInfo *info =
3232                 (GtkTreeViewColumnCellInfo *)list->data;
3233
3234               *right += info->real_width;
3235             }
3236         }
3237     }
3238 }