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