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