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