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