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