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