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