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