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