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