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