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