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