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