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