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