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