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