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