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