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