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