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