]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
s/GTK_TREE_COLUMN/GTK_TREE_VIEW_COLUMN
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.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
21 #include "gtktreeview.h"
22 #include "gtkrbtree.h"
23 #include "gtktreednd.h"
24 #include "gtktreeprivate.h"
25 #include "gtkcellrenderer.h"
26 #include "gtksignal.h"
27 #include "gtkmain.h"
28 #include "gtkbutton.h"
29 #include "gtkalignment.h"
30 #include "gtklabel.h"
31 #include "gtkhbox.h"
32 #include "gtkarrow.h"
33 #include "gtkintl.h"
34
35 #include <gdk/gdkkeysyms.h>
36
37
38 /* The "background" areas of all rows/cells add up to cover the entire tree.
39  * The background includes all inter-row and inter-cell spacing.
40  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
41  * i.e. just the cells, no spacing.
42  */
43
44 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (_gtk_rbtree_node_find_offset ((tree), (node)) + TREE_VIEW_HEADER_HEIGHT ((tree_view)))
45 #define CELL_FIRST_PIXEL(tree_view,tree,node) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + TREE_VIEW_VERTICAL_SEPARATOR/2)
46
47 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
48 #define CELL_HEIGHT(node) (BACKGROUND_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPARATOR);
49
50 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view))
51 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view))
52
53 typedef struct _GtkTreeViewChild GtkTreeViewChild;
54
55 struct _GtkTreeViewChild
56 {
57   GtkWidget *widget;
58   gint x;
59   gint y;
60 };
61
62 enum
63 {
64   ROW_ACTIVATED,
65   LAST_SIGNAL
66 };
67
68 enum {
69   PROP_0,
70
71   PROP_MODEL,
72   PROP_HADJUSTMENT,
73   PROP_VADJUSTMENT,
74   PROP_HEADERS_VISIBLE,
75   PROP_HEADERS_CLICKABLE,
76   PROP_EXPANDER_COLUMN,
77   PROP_RULES_HINT
78 };
79
80 static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);
81 static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
82 static void     gtk_tree_view_set_property         (GObject         *object,
83                                                     guint            prop_id,
84                                                     const GValue    *value,
85                                                     GParamSpec      *pspec);
86 static void     gtk_tree_view_get_property         (GObject         *object,
87                                                     guint            prop_id,
88                                                     GValue          *value,
89                                                     GParamSpec      *pspec);
90 /* o signals */
91 static void     gtk_tree_view_finalize             (GObject          *object);
92
93 /* object signals */
94 static void     gtk_tree_view_destroy              (GtkObject        *object);
95
96 /* widget signals */
97 static void     gtk_tree_view_setup_model          (GtkTreeView      *tree_view);
98 static void     gtk_tree_view_realize              (GtkWidget        *widget);
99 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
100 static void     gtk_tree_view_map                  (GtkWidget        *widget);
101 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
102                                                     GtkRequisition   *requisition);
103 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
104                                                     GtkAllocation    *allocation);
105 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
106                                                     GdkEventExpose   *event);
107 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
108                                                     GdkEventMotion   *event);
109 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
110                                                     GdkEventCrossing *event);
111 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
112                                                     GdkEventCrossing *event);
113 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
114                                                     GdkEventButton   *event);
115 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
116                                                     GdkEventButton   *event);
117 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
118                                                     GtkWidget        *child);
119 static void     gtk_tree_view_draw_focus           (GtkWidget        *widget);
120 static gint     gtk_tree_view_focus_in             (GtkWidget        *widget,
121                                                     GdkEventFocus    *event);
122 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
123                                                     GdkEventFocus    *event);
124 static gint     gtk_tree_view_focus                (GtkContainer     *container,
125                                                     GtkDirectionType  direction);
126
127 /* container signals */
128 static void     gtk_tree_view_remove               (GtkContainer     *container,
129                                                     GtkWidget        *widget);
130 static void     gtk_tree_view_forall               (GtkContainer     *container,
131                                                     gboolean          include_internals,
132                                                     GtkCallback       callback,
133                                                     gpointer          callback_data);
134
135 /* Source side drag signals */
136 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
137                                             GdkDragContext   *context);
138 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
139                                             GdkDragContext   *context);
140 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
141                                             GdkDragContext   *context,
142                                             GtkSelectionData *selection_data,
143                                             guint             info,
144                                             guint             time);
145 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
146                                             GdkDragContext   *context);
147
148 /* Target side drag signals */
149 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
150                                                   GdkDragContext   *context,
151                                                   guint             time);
152 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
153                                                   GdkDragContext   *context,
154                                                   gint              x,
155                                                   gint              y,
156                                                   guint             time);
157 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
158                                                   GdkDragContext   *context,
159                                                   gint              x,
160                                                   gint              y,
161                                                   guint             time);
162 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
163                                                   GdkDragContext   *context,
164                                                   gint              x,
165                                                   gint              y,
166                                                   GtkSelectionData *selection_data,
167                                                   guint             info,
168                                                   guint             time);
169
170 /* tree_model signals */
171 static void     gtk_tree_view_set_adjustments      (GtkTreeView      *tree_view,
172                                                     GtkAdjustment    *hadj,
173                                                     GtkAdjustment    *vadj);
174 static void     gtk_tree_view_changed              (GtkTreeModel     *model,
175                                                     GtkTreePath      *path,
176                                                     GtkTreeIter      *iter,
177                                                     gpointer          data);
178 static void     gtk_tree_view_inserted             (GtkTreeModel     *model,
179                                                     GtkTreePath      *path,
180                                                     GtkTreeIter      *iter,
181                                                     gpointer          data);
182 static void     gtk_tree_view_has_child_toggled    (GtkTreeModel     *model,
183                                                     GtkTreePath      *path,
184                                                     GtkTreeIter      *iter,
185                                                     gpointer          data);
186 static void     gtk_tree_view_deleted              (GtkTreeModel     *model,
187                                                     GtkTreePath      *path,
188                                                     gpointer          data);
189
190 /* Internal functions */
191 static void     gtk_tree_view_unref_tree           (GtkTreeView      *tree_view,
192                                                     GtkRBTree        *tree);
193 static void     gtk_tree_view_queue_draw_node      (GtkTreeView      *tree_view,
194                                                     GtkRBTree        *tree,
195                                                     GtkRBNode        *node,
196                                                     GdkRectangle     *clip_rect);
197 static void     gtk_tree_view_queue_draw_path      (GtkTreeView      *tree_view,
198                                                     GtkTreePath      *path,
199                                                     GdkRectangle     *clip_rect);
200 static void     gtk_tree_view_draw_arrow           (GtkTreeView      *tree_view,
201                                                     GtkRBTree        *tree,
202                                                     GtkRBNode        *node,
203                                                     gint              x,
204                                                     gint              y);
205 static void     gtk_tree_view_get_arrow_xrange     (GtkTreeView      *tree_view,
206                                                     gint              *x1,
207                                                     gint              *x2);
208 static gint     gtk_tree_view_new_column_width     (GtkTreeView      *tree_view,
209                                                     gint              i,
210                                                     gint             *x);
211 static void     gtk_tree_view_adjustment_changed   (GtkAdjustment    *adjustment,
212                                                     GtkTreeView      *tree_view);
213 static gint     gtk_tree_view_insert_iter_height   (GtkTreeView      *tree_view,
214                                                     GtkRBTree        *tree,
215                                                     GtkTreeIter      *iter,
216                                                     gint              depth);
217 static void     gtk_tree_view_build_tree           (GtkTreeView      *tree_view,
218                                                     GtkRBTree        *tree,
219                                                     GtkTreeIter      *iter,
220                                                     gint              depth,
221                                                     gboolean          recurse,
222                                                     gboolean          calc_bounds);
223 static void     gtk_tree_view_calc_size            (GtkTreeView      *priv,
224                                                     GtkRBTree        *tree,
225                                                     GtkTreeIter      *iter,
226                                                     gint              depth);
227 static gboolean gtk_tree_view_discover_dirty_iter  (GtkTreeView      *tree_view,
228                                                     GtkTreeIter      *iter,
229                                                     gint              depth,
230                                                     gint             *height);
231 static void     gtk_tree_view_discover_dirty       (GtkTreeView      *tree_view,
232                                                     GtkRBTree        *tree,
233                                                     GtkTreeIter      *iter,
234                                                     gint              depth);
235 static void     gtk_tree_view_check_dirty          (GtkTreeView      *tree_view);
236 #if 0
237 static void     gtk_tree_view_create_button        (GtkTreeView      *tree_view,
238                                                     gint              i);
239 static void     gtk_tree_view_create_buttons       (GtkTreeView      *tree_view);
240 #endif
241 static void     gtk_tree_view_clamp_node_visible   (GtkTreeView      *tree_view,
242                                                     GtkRBTree        *tree,
243                                                     GtkRBNode        *node);
244 static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
245                                                         GdkEventMotion   *event);
246 static void     _gtk_tree_view_update_col_width    (GtkTreeView      *tree_view);
247 static void     gtk_tree_view_row_activated        (GtkTreeView      *tree_view,
248                                                     GtkTreeViewColumn *column);
249
250 static GtkContainerClass *parent_class = NULL;
251 static guint tree_view_signals[LAST_SIGNAL] = { 0 };
252
253 /* Class Functions */
254 GtkType
255 gtk_tree_view_get_type (void)
256 {
257   static GtkType tree_view_type = 0;
258
259   if (!tree_view_type)
260     {
261       static const GTypeInfo tree_view_info =
262       {
263         sizeof (GtkTreeViewClass),
264         NULL,           /* base_init */
265         NULL,           /* base_finalize */
266         (GClassInitFunc) gtk_tree_view_class_init,
267         NULL,           /* class_finalize */
268         NULL,           /* class_data */
269         sizeof (GtkTreeView),
270         0,              /* n_preallocs */
271         (GInstanceInitFunc) gtk_tree_view_init
272       };
273
274       tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
275     }
276
277   return tree_view_type;
278 }
279
280 static void
281 gtk_tree_view_class_init (GtkTreeViewClass *class)
282 {
283   GObjectClass *o_class;
284   GtkObjectClass *object_class;
285   GtkWidgetClass *widget_class;
286   GtkContainerClass *container_class;
287
288   o_class = (GObjectClass *) class;
289   object_class = (GtkObjectClass *) class;
290   widget_class = (GtkWidgetClass *) class;
291   container_class = (GtkContainerClass *) class;
292
293   parent_class = g_type_class_peek_parent (class);
294
295   o_class->finalize = gtk_tree_view_finalize;
296   o_class->set_property = gtk_tree_view_set_property;
297   o_class->get_property = gtk_tree_view_get_property;
298
299   object_class->destroy = gtk_tree_view_destroy;
300
301   widget_class->realize = gtk_tree_view_realize;
302   widget_class->unrealize = gtk_tree_view_unrealize;
303   widget_class->map = gtk_tree_view_map;
304   widget_class->size_request = gtk_tree_view_size_request;
305   widget_class->size_allocate = gtk_tree_view_size_allocate;
306   widget_class->expose_event = gtk_tree_view_expose;
307   widget_class->motion_notify_event = gtk_tree_view_motion;
308   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
309   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
310   widget_class->button_press_event = gtk_tree_view_button_press;
311   widget_class->button_release_event = gtk_tree_view_button_release;
312   widget_class->focus_in_event = gtk_tree_view_focus_in;
313   widget_class->focus_out_event = gtk_tree_view_focus_out;
314
315   widget_class->drag_begin = gtk_tree_view_drag_begin;
316   widget_class->drag_end = gtk_tree_view_drag_end;
317   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
318   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
319
320   widget_class->drag_leave = gtk_tree_view_drag_leave;
321   widget_class->drag_motion = gtk_tree_view_drag_motion;
322   widget_class->drag_drop = gtk_tree_view_drag_drop;
323   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
324
325   container_class->forall = gtk_tree_view_forall;
326   container_class->remove = gtk_tree_view_remove;
327   container_class->focus = gtk_tree_view_focus;
328
329   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
330
331   g_object_class_install_property (o_class,
332                                    PROP_MODEL,
333                                    g_param_spec_object ("model",
334                                                         _("TreeView Model"),
335                                                         _("The model for the tree view"),
336                                                         GTK_TYPE_TREE_MODEL,
337                                                         G_PARAM_READWRITE));
338
339   g_object_class_install_property (o_class,
340                                    PROP_HADJUSTMENT,
341                                    g_param_spec_object ("hadjustment",
342                                                         _("Horizontal Adjustment"),
343                                                         _("Horizontal Adjustment for the widget"),
344                                                         GTK_TYPE_ADJUSTMENT,
345                                                         G_PARAM_READWRITE));
346
347   g_object_class_install_property (o_class,
348                                    PROP_VADJUSTMENT,
349                                    g_param_spec_object ("vadjustment",
350                                                         _("Vertical Adjustment"),
351                                                         _("Vertical Adjustment for the widget"),
352                                                         GTK_TYPE_ADJUSTMENT,
353                                                         G_PARAM_READWRITE));
354
355   g_object_class_install_property (o_class,
356                                    PROP_HEADERS_VISIBLE,
357                                    g_param_spec_boolean ("headers_visible",
358                                                          _("Visible"),
359                                                          _("Show the column header buttons"),
360                                                          FALSE,
361                                                          G_PARAM_READWRITE));
362
363   g_object_class_install_property (o_class,
364                                    PROP_HEADERS_CLICKABLE,
365                                    g_param_spec_boolean ("headers_clickable",
366                                                          _("Headers Clickable"),
367                                                          _("Column headers respond to click events"),
368                                                          FALSE,
369                                                          G_PARAM_READWRITE));
370
371   g_object_class_install_property (o_class,
372                                    PROP_EXPANDER_COLUMN,
373                                    g_param_spec_uint ("expander_column",
374                                                       _("Expand Column"),
375                                                       _("Set the column number for the expander column"),
376                                                       0,
377                                                       G_MAXINT,
378                                                       0,
379                                                       G_PARAM_READWRITE));
380
381   g_object_class_install_property (o_class,
382                                    PROP_RULES_HINT,
383                                    g_param_spec_boolean ("rules_hint",
384                                                          _("Rules Hint"),
385                                                          _("Set a hint to the theme engine to draw rows in alternating colors"),
386                                                          FALSE,
387                                                          G_PARAM_READWRITE));
388
389   widget_class->set_scroll_adjustments_signal =
390     gtk_signal_new ("set_scroll_adjustments",
391                     GTK_RUN_LAST,
392                     GTK_CLASS_TYPE (object_class),
393                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
394                     gtk_marshal_VOID__OBJECT_OBJECT,
395                     GTK_TYPE_NONE, 2,
396                     GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
397
398   tree_view_signals[ROW_ACTIVATED] = gtk_signal_new ("row_activated",
399                                                      GTK_RUN_LAST | GTK_RUN_ACTION,
400                                                      GTK_CLASS_TYPE (object_class),
401                                                      GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
402                                                      gtk_marshal_VOID__OBJECT,
403                                                      GTK_TYPE_NONE, 1,
404                                                      GTK_TYPE_TREE_VIEW_COLUMN);
405
406 }
407
408 static void
409 gtk_tree_view_init (GtkTreeView *tree_view)
410 {
411   tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
412
413   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
414
415   tree_view->priv->model = NULL;
416   tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
417   tree_view->priv->tab_offset = TREE_VIEW_EXPANDER_WIDTH;
418   tree_view->priv->n_columns = 0;
419   tree_view->priv->columns = NULL;
420   tree_view->priv->button_pressed_node = NULL;
421   tree_view->priv->button_pressed_tree = NULL;
422   tree_view->priv->prelight_node = NULL;
423   tree_view->priv->header_height = 1;
424   tree_view->priv->x_drag = 0;
425   tree_view->priv->drag_pos = -1;
426   tree_view->priv->selection = NULL;
427   tree_view->priv->anchor = NULL;
428   tree_view->priv->cursor = NULL;
429   tree_view->priv->header_has_focus = FALSE;
430   tree_view->priv->pressed_button = -1;
431   tree_view->priv->press_start_x = -1;
432   tree_view->priv->press_start_y = -1;
433
434   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
435   _gtk_tree_view_update_size (tree_view);
436 }
437
438
439 /* Object methods
440  */
441
442 static void
443 gtk_tree_view_finalize (GObject *object)
444 {
445   GtkTreeView *tree_view = (GtkTreeView *) object;
446
447   g_free (tree_view->priv);
448
449   if (G_OBJECT_CLASS (parent_class)->finalize)
450     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
451 }
452
453 static void
454 gtk_tree_view_destroy (GtkObject *object)
455 {
456   GtkTreeView *tree_view = (GtkTreeView *) object;
457   GList *list;
458
459
460   if (tree_view->priv->tree != NULL)
461     {
462       gtk_tree_view_unref_tree (tree_view, tree_view->priv->tree);
463       _gtk_rbtree_free (tree_view->priv->tree);
464       tree_view->priv->tree = NULL;
465     }
466
467   if (tree_view->priv->model != NULL)
468     {
469       g_object_unref (G_OBJECT (tree_view->priv->model));
470       tree_view->priv->model = NULL;
471     }
472
473   if (tree_view->priv->columns != NULL)
474     {
475       for (list = tree_view->priv->columns; list; list = list->next)
476         g_object_unref (G_OBJECT (list->data));
477       g_list_free (tree_view->priv->columns);
478       tree_view->priv->columns = NULL;
479     }
480
481   if (tree_view->priv->selection != NULL)
482     {
483       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
484       g_object_unref (tree_view->priv->selection);
485       tree_view->priv->selection = NULL;
486     }
487
488   if (tree_view->priv->anchor != NULL)
489     {
490       gtk_tree_row_reference_free (tree_view->priv->anchor);
491       tree_view->priv->anchor = NULL;
492     }
493
494   if (tree_view->priv->scroll_to_path != NULL)
495     {
496       gtk_tree_path_free (tree_view->priv->scroll_to_path);
497       tree_view->priv->scroll_to_path = NULL;
498     }
499
500   if (tree_view->priv->drag_dest_row != NULL)
501     {
502       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
503       tree_view->priv->drag_dest_row = NULL;
504     }
505
506   if (tree_view->priv->cursor)
507     {
508       gtk_tree_row_reference_free (tree_view->priv->cursor);
509       tree_view->priv->cursor = NULL;
510     }
511
512   if (GTK_OBJECT_CLASS (parent_class)->destroy)
513     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
514 }
515
516 /* Property handlers
517  */
518
519 static void
520 gtk_tree_view_set_property (GObject         *object,
521                             guint            prop_id,
522                             const GValue    *value,
523                             GParamSpec      *pspec)
524 {
525   GtkTreeView *tree_view;
526
527   tree_view = GTK_TREE_VIEW (object);
528
529   switch (prop_id)
530     {
531     case PROP_MODEL:
532       gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (g_value_get_object (value)));
533       break;
534     case PROP_HADJUSTMENT:
535       gtk_tree_view_set_hadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
536       break;
537     case PROP_VADJUSTMENT:
538       gtk_tree_view_set_vadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
539       break;
540     case PROP_HEADERS_VISIBLE:
541       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
542       break;
543     case PROP_HEADERS_CLICKABLE:
544       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
545       break;
546     case PROP_EXPANDER_COLUMN:
547       gtk_tree_view_set_expander_column (tree_view, g_value_get_uint (value));
548       break;
549     case PROP_RULES_HINT:
550       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
551       break;
552     default:
553       break;
554     }
555 }
556
557 static void
558 gtk_tree_view_get_property (GObject         *object,
559                             guint            prop_id,
560                             GValue          *value,
561                             GParamSpec      *pspec)
562 {
563   GtkTreeView *tree_view;
564
565   tree_view = GTK_TREE_VIEW (object);
566
567   switch (prop_id)
568     {
569     case PROP_MODEL:
570       g_value_set_object (value, G_OBJECT (tree_view->priv->model));
571       break;
572     case PROP_HADJUSTMENT:
573       g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
574       break;
575     case PROP_VADJUSTMENT:
576       g_value_set_object (value, G_OBJECT (tree_view->priv->vadjustment));
577       break;
578     case PROP_HEADERS_VISIBLE:
579       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
580       break;
581     case PROP_HEADERS_CLICKABLE:
582       /* g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view)); */
583       break;
584     case PROP_EXPANDER_COLUMN:
585       g_value_set_uint (value, tree_view->priv->expander_column);
586       break;
587     case PROP_RULES_HINT:
588       g_value_set_boolean (value, tree_view->priv->has_rules);
589       break;
590     default:
591       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
592       break;
593     }
594 }
595
596 /* Widget methods
597  */
598
599 static void
600 gtk_tree_view_realize (GtkWidget *widget)
601 {
602   GList *tmp_list;
603   GtkTreeView *tree_view;
604   GdkGCValues values;
605   GdkWindowAttr attributes;
606   gint attributes_mask;
607
608   g_return_if_fail (widget != NULL);
609   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
610
611   tree_view = GTK_TREE_VIEW (widget);
612
613   gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
614   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
615
616   /* Make the main, clipping window */
617   attributes.window_type = GDK_WINDOW_CHILD;
618   attributes.x = widget->allocation.x;
619   attributes.y = widget->allocation.y;
620   attributes.width = widget->allocation.width;
621   attributes.height = widget->allocation.height;
622   attributes.wclass = GDK_INPUT_OUTPUT;
623   attributes.visual = gtk_widget_get_visual (widget);
624   attributes.colormap = gtk_widget_get_colormap (widget);
625   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
626
627   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
628
629   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
630                                    &attributes, attributes_mask);
631   gdk_window_set_user_data (widget->window, widget);
632
633   /* Make the window for the tree */
634   attributes.x = 0;
635   attributes.y = 0;
636   attributes.width = tree_view->priv->width;
637   attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
638   attributes.event_mask = GDK_EXPOSURE_MASK |
639     GDK_SCROLL_MASK |
640     GDK_POINTER_MOTION_MASK |
641     GDK_ENTER_NOTIFY_MASK |
642     GDK_LEAVE_NOTIFY_MASK |
643     GDK_BUTTON_PRESS_MASK |
644     GDK_BUTTON_RELEASE_MASK |
645     gtk_widget_get_events (widget);
646
647   tree_view->priv->bin_window = gdk_window_new (widget->window,
648                                                 &attributes, attributes_mask);
649   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
650
651   /* Make the column header window */
652   attributes.x = 0;
653   attributes.y = 0;
654   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
655   attributes.height = tree_view->priv->header_height;
656   attributes.event_mask = (GDK_EXPOSURE_MASK |
657                            GDK_SCROLL_MASK |
658                            GDK_BUTTON_PRESS_MASK |
659                            GDK_BUTTON_RELEASE_MASK |
660                            GDK_KEY_PRESS_MASK |
661                            GDK_KEY_RELEASE_MASK) |
662     gtk_widget_get_events (widget);
663
664   tree_view->priv->header_window = gdk_window_new (widget->window,
665                                                    &attributes, attributes_mask);
666   gdk_window_set_user_data (tree_view->priv->header_window, widget);
667
668
669   values.foreground = (widget->style->white.pixel==0 ?
670                        widget->style->black:widget->style->white);
671   values.function = GDK_XOR;
672   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
673   tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
674                                                     &values,
675                                                     GDK_GC_FOREGROUND |
676                                                     GDK_GC_FUNCTION |
677                                                     GDK_GC_SUBWINDOW);
678   /* Add them all up. */
679   widget->style = gtk_style_attach (widget->style, widget->window);
680   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
681   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
682   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
683
684   tmp_list = tree_view->priv->children;
685   while (tmp_list)
686     {
687       GtkTreeViewChild *child = tmp_list->data;
688       tmp_list = tmp_list->next;
689
690       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
691     }
692
693   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
694     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
695
696   _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
697
698   if (tree_view->priv->scroll_to_path != NULL ||
699       tree_view->priv->scroll_to_column != NULL)
700     {
701       gtk_tree_view_scroll_to_cell (tree_view,
702                                     tree_view->priv->scroll_to_path,
703                                     tree_view->priv->scroll_to_column,
704                                     tree_view->priv->scroll_to_row_align,
705                                     tree_view->priv->scroll_to_col_align);
706       if (tree_view->priv->scroll_to_path)
707         {
708           gtk_tree_path_free (tree_view->priv->scroll_to_path);
709           tree_view->priv->scroll_to_path = NULL;
710         }
711       tree_view->priv->scroll_to_column = NULL;
712     }
713 }
714
715 static void
716 gtk_tree_view_unrealize (GtkWidget *widget)
717 {
718   GtkTreeView *tree_view;
719   GList *list;
720
721   g_return_if_fail (widget != NULL);
722   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
723
724   tree_view = GTK_TREE_VIEW (widget);
725
726   if (tree_view->priv->scroll_timeout != 0)
727     {
728       gtk_timeout_remove (tree_view->priv->scroll_timeout);
729       tree_view->priv->scroll_timeout = 0;
730     }
731
732   if (tree_view->priv->open_dest_timeout != 0)
733     {
734       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
735       tree_view->priv->open_dest_timeout = 0;
736     }
737
738   for (list = tree_view->priv->columns; list; list = list->next)
739     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
740
741   gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
742   gdk_window_destroy (tree_view->priv->bin_window);
743   tree_view->priv->bin_window = NULL;
744
745   gdk_window_set_user_data (tree_view->priv->header_window, NULL);
746   gdk_window_destroy (tree_view->priv->header_window);
747   tree_view->priv->header_window = NULL;
748
749   gdk_cursor_destroy (tree_view->priv->cursor_drag);
750   gdk_gc_destroy (tree_view->priv->xor_gc);
751
752   /* GtkWidget::unrealize destroys children and widget->window */
753
754   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
755     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
756 }
757
758 static void
759 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
760 {
761   GList *list;
762
763   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
764
765   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
766     {
767       GtkTreeViewColumn *column;
768
769       for (list = tree_view->priv->columns; list; list = list->next)
770         {
771           column = list->data;
772           if (GTK_WIDGET_VISIBLE (column->button) &&
773               !GTK_WIDGET_MAPPED (column->button))
774             gtk_widget_map (column->button);
775         }
776       for (list = tree_view->priv->columns; list; list = list->next)
777         {
778           column = list->data;
779           if (column->visible == FALSE)
780             continue;
781           if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
782             {
783               gdk_window_raise (column->window);
784               gdk_window_show (column->window);
785             }
786           else
787             gdk_window_hide (column->window);
788         }
789       gdk_window_show (tree_view->priv->header_window);
790     }
791 }
792
793 static void
794 gtk_tree_view_map (GtkWidget *widget)
795 {
796   GList *tmp_list;
797   GtkTreeView *tree_view;
798
799   g_return_if_fail (widget != NULL);
800   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
801
802   tree_view = GTK_TREE_VIEW (widget);
803
804   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
805
806   tmp_list = tree_view->priv->children;
807   while (tmp_list)
808     {
809       GtkTreeViewChild *child = tmp_list->data;
810       tmp_list = tmp_list->next;
811
812       if (GTK_WIDGET_VISIBLE (child->widget))
813         {
814           if (!GTK_WIDGET_MAPPED (child->widget))
815             gtk_widget_map (child->widget);
816         }
817     }
818   gdk_window_show (tree_view->priv->bin_window);
819
820   gtk_tree_view_map_buttons (tree_view);
821
822   gdk_window_show (widget->window);
823 }
824
825 static void
826 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
827 {
828   GList *list;
829
830   tree_view->priv->header_height = 1;
831
832   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
833     {
834       for (list = tree_view->priv->columns; list; list = list->next)
835         {
836           GtkRequisition requisition;
837           GtkTreeViewColumn *column;
838
839           column = list->data;
840
841           gtk_widget_size_request (column->button, &requisition);
842
843           gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
844           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
845         }
846     }
847 }
848
849 static void
850 gtk_tree_view_size_request (GtkWidget      *widget,
851                             GtkRequisition *requisition)
852 {
853   GtkTreeView *tree_view;
854   GList *tmp_list;
855
856   g_return_if_fail (widget != NULL);
857   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
858
859   tree_view = GTK_TREE_VIEW (widget);
860
861   requisition->width = 200;
862   requisition->height = 200;
863
864   tmp_list = tree_view->priv->children;
865
866   while (tmp_list)
867     {
868       GtkTreeViewChild *child = tmp_list->data;
869       GtkRequisition child_requisition;
870
871       tmp_list = tmp_list->next;
872
873       if (GTK_WIDGET_VISIBLE (child->widget))
874         gtk_widget_size_request (child->widget, &child_requisition);
875     }
876
877   gtk_tree_view_size_request_buttons (tree_view);
878 }
879
880 static void
881 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
882 {
883   GtkTreeView *tree_view;
884   GList *list;
885   GtkTreeViewColumn *column;
886   GtkAllocation allocation;
887   gint width = 0;
888
889   tree_view = GTK_TREE_VIEW (widget);
890
891   allocation.y = 0;
892   allocation.height = tree_view->priv->header_height;
893
894   for (list = tree_view->priv->columns; list != NULL; list = list->next)
895     {
896       column = list->data;
897
898       if (!column->visible)
899         continue;
900
901       allocation.x = width;
902       allocation.width = column->displayed_width;
903       width += column->width;
904       gtk_widget_size_allocate (column->button, &allocation);
905
906       if (column->window)
907         gdk_window_move_resize (column->window,
908                                 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
909                                 allocation.y,
910                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
911     }
912 }
913
914 static void
915 gtk_tree_view_size_allocate (GtkWidget     *widget,
916                              GtkAllocation *allocation)
917 {
918   GList *tmp_list;
919   GtkTreeView *tree_view;
920
921   g_return_if_fail (widget != NULL);
922   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
923
924   widget->allocation = *allocation;
925
926   tree_view = GTK_TREE_VIEW (widget);
927
928   gtk_tree_view_check_dirty (tree_view);
929
930   tmp_list = tree_view->priv->children;
931
932   while (tmp_list)
933     {
934       GtkAllocation allocation;
935       GtkRequisition requisition;
936
937       GtkTreeViewChild *child = tmp_list->data;
938       tmp_list = tmp_list->next;
939
940       allocation.x = child->x;
941       allocation.y = child->y;
942       gtk_widget_get_child_requisition (child->widget, &requisition);
943       allocation.width = requisition.width;
944       allocation.height = requisition.height;
945
946       gtk_widget_size_allocate (child->widget, &allocation);
947     }
948
949   if (GTK_WIDGET_REALIZED (widget))
950     {
951       gdk_window_move_resize (widget->window,
952                               allocation->x, allocation->y,
953                               allocation->width, allocation->height);
954
955       gdk_window_move_resize (tree_view->priv->header_window,
956                               0, 0,
957                               MAX (tree_view->priv->width, allocation->width),
958                               tree_view->priv->header_height);
959
960       if (tree_view->priv->width < allocation->width)
961         gdk_window_resize (tree_view->priv->bin_window,
962                            allocation->width,
963                            tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
964
965       _gtk_tree_view_update_col_width (tree_view);
966     }
967
968   gtk_tree_view_size_allocate_buttons (widget);
969
970   tree_view->priv->hadjustment->page_size = allocation->width;
971   tree_view->priv->hadjustment->page_increment = allocation->width / 2;
972   tree_view->priv->hadjustment->lower = 0;
973   tree_view->priv->hadjustment->upper = tree_view->priv->width;
974
975   if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
976     tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
977   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
978
979   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
980   tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
981   tree_view->priv->vadjustment->lower = 0;
982   tree_view->priv->vadjustment->upper = tree_view->priv->height;
983
984   if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
985     gtk_adjustment_set_value (tree_view->priv->vadjustment,
986                               (gfloat) MAX (tree_view->priv->height - allocation->height, 0));
987
988   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
989
990 }
991
992 GdkPixmap*
993 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
994                                     GtkTreePath  *path)
995 {
996   GtkTreeIter   iter;
997   GtkRBTree    *tree;
998   GtkRBNode    *node;
999   GtkCellRenderer *cell;
1000   gint i;
1001   gint cell_offset;
1002   GList *list;
1003   GdkRectangle background_area;
1004   GtkWidget *widget;
1005   gint depth;
1006   /* start drawing inside the black outline */
1007   gint x = 1, y = 1;
1008   GdkDrawable *drawable;
1009   gint bin_window_width;
1010
1011   widget = GTK_WIDGET (tree_view);
1012
1013   depth = gtk_tree_path_get_depth (path);
1014
1015   _gtk_tree_view_find_node (tree_view,
1016                             path,
1017                             &tree,
1018                             &node);
1019
1020   if (tree == NULL)
1021     return NULL;
1022
1023   if (!gtk_tree_model_get_iter (tree_view->priv->model,
1024                                 &iter,
1025                                 path))
1026     return NULL;
1027
1028   cell_offset = x;
1029
1030   background_area.y = y;
1031   background_area.height = BACKGROUND_HEIGHT (node);
1032
1033   gdk_drawable_get_size (tree_view->priv->bin_window,
1034                          &bin_window_width, NULL);
1035
1036   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
1037                              bin_window_width + 2,
1038                              background_area.height + 2,
1039                              -1);
1040
1041   gdk_draw_rectangle (drawable,
1042                       widget->style->base_gc[GTK_WIDGET_STATE (widget)],
1043                       TRUE,
1044                       0, 0,
1045                       bin_window_width + 2,
1046                       background_area.height + 2);
1047
1048   gdk_draw_rectangle (drawable,
1049                       widget->style->black_gc,
1050                       FALSE,
1051                       0, 0,
1052                       bin_window_width + 1,
1053                       background_area.height + 1);
1054
1055   for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1056     {
1057       GtkTreeViewColumn *column = list->data;
1058       GdkRectangle cell_area;
1059       gboolean visible;
1060
1061       if (!column->visible)
1062         continue;
1063
1064       cell = column->cell;
1065       gtk_tree_view_column_set_cell_data (column,
1066                                           tree_view->priv->model,
1067                                           &iter);
1068
1069       background_area.x = cell_offset;
1070       background_area.width = column->displayed_width;
1071
1072       cell_area = background_area;
1073
1074       cell_area.y += TREE_VIEW_VERTICAL_SEPARATOR / 2;
1075       cell_area.height -= TREE_VIEW_VERTICAL_SEPARATOR;
1076
1077       if (i == tree_view->priv->expander_column &&
1078           TREE_VIEW_DRAW_EXPANDERS(tree_view))
1079         {
1080           cell_area.x += depth * tree_view->priv->tab_offset;
1081           cell_area.width -= depth * tree_view->priv->tab_offset;
1082         }
1083
1084       g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
1085       if (visible)
1086         gtk_cell_renderer_render (cell,
1087                                   drawable,
1088                                   widget,
1089                                   &background_area,
1090                                   &cell_area,
1091                                   NULL,
1092                                   0);
1093
1094       cell_offset += column->displayed_width;
1095     }
1096
1097   return drawable;
1098 }
1099
1100 /* Warning: Very scary function.
1101  * Modify at your own risk
1102  */
1103 static gboolean
1104 gtk_tree_view_bin_expose (GtkWidget      *widget,
1105                           GdkEventExpose *event)
1106 {
1107   GtkTreeView *tree_view;
1108   GtkTreePath *path;
1109   GtkRBTree *tree;
1110   GList *list;
1111   GtkRBNode *node;
1112   GtkRBNode *cursor = NULL;
1113   GtkRBTree *cursor_tree = NULL;
1114   GtkRBNode *drag_highlight = NULL;
1115   GtkRBTree *drag_highlight_tree = NULL;
1116   GtkTreeIter iter;
1117   GtkCellRenderer *cell;
1118   gint new_y;
1119   gint y_offset, x_offset, cell_offset;
1120   gint i, max_height;
1121   gint depth;
1122   GdkRectangle background_area;
1123   GdkRectangle cell_area;
1124   guint flags;
1125   gint highlight_x;
1126   gint bin_window_width;
1127   GtkTreePath *cursor_path;
1128   GtkTreePath *drag_dest_path;
1129   GList *last_column;
1130
1131   g_return_val_if_fail (widget != NULL, FALSE);
1132   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1133
1134   tree_view = GTK_TREE_VIEW (widget);
1135
1136   if (tree_view->priv->tree == NULL)
1137     return TRUE;
1138
1139   gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
1140   /* we want to account for a potential HEADER offset.
1141    * That is, if the header exists, we want to offset our event by its
1142    * height to find the right node.
1143    */
1144   new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
1145
1146   /* y_offset is the */
1147
1148   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1149                                        TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1150                                        &tree,
1151                                        &node) + new_y - event->area.y;
1152   if (node == NULL)
1153     return TRUE;
1154
1155   /* find the path for the node */
1156   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
1157                                    tree,
1158                                    node);
1159   gtk_tree_model_get_iter (tree_view->priv->model,
1160                            &iter,
1161                            path);
1162   depth = gtk_tree_path_get_depth (path);
1163   gtk_tree_path_free (path);
1164
1165   cursor_path = NULL;
1166   drag_dest_path = NULL;
1167
1168   if (tree_view->priv->cursor)
1169     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
1170
1171   if (cursor_path)
1172     _gtk_tree_view_find_node (tree_view, cursor_path,
1173                               &cursor_tree, &cursor);
1174
1175   if (tree_view->priv->drag_dest_row)
1176     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
1177
1178   if (drag_dest_path)
1179     _gtk_tree_view_find_node (tree_view, drag_dest_path,
1180                               &drag_highlight_tree, &drag_highlight);
1181
1182   gdk_drawable_get_size (tree_view->priv->bin_window,
1183                          &bin_window_width, NULL);
1184
1185   for (last_column = g_list_last (tree_view->priv->columns);
1186        last_column &&
1187          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
1188          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
1189        last_column = last_column->prev)
1190     ;
1191
1192   /* Actually process the expose event.  To do this, we want to
1193    * start at the first node of the event, and walk the tree in
1194    * order, drawing each successive node.
1195    */
1196
1197   do
1198     {
1199       /* Need to think about this more.
1200          if (tree_view->priv->show_expanders)
1201          max_height = MAX (TREE_VIEW_EXPANDER_MIN_HEIGHT, GTK_RBNODE_GET_HEIGHT (node));
1202          else
1203       */
1204       gboolean parity;
1205
1206       max_height = BACKGROUND_HEIGHT (node);
1207
1208       x_offset = -event->area.x;
1209       cell_offset = 0;
1210       highlight_x = 0; /* should match x coord of first cell */
1211
1212       background_area.y = y_offset + event->area.y;
1213       background_area.height = max_height;
1214       flags = 0;
1215
1216       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
1217         flags |= GTK_CELL_RENDERER_PRELIT;
1218
1219       parity = _gtk_rbtree_node_find_parity (tree, node);
1220
1221       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1222         flags |= GTK_CELL_RENDERER_SELECTED;
1223
1224       for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1225         {
1226           GtkTreeViewColumn *column = list->data;
1227           const gchar *detail = NULL;
1228
1229           if (!column->visible)
1230             continue;
1231
1232           if (cell_offset > event->area.x + event->area.width ||
1233               cell_offset + column->displayed_width < event->area.x)
1234             {
1235               cell_offset += column->displayed_width;
1236               continue;
1237             }
1238
1239           if (column->show_sort_indicator)
1240             flags |= GTK_CELL_RENDERER_SORTED;
1241           else
1242             flags &= ~GTK_CELL_RENDERER_SORTED;
1243
1244           cell = column->cell;
1245           gtk_tree_view_column_set_cell_data (column,
1246                                               tree_view->priv->model,
1247                                               &iter);
1248
1249           background_area.x = cell_offset;
1250           background_area.width = column->displayed_width;
1251
1252           cell_area = background_area;
1253           cell_area.y += TREE_VIEW_VERTICAL_SEPARATOR / 2;
1254           cell_area.height -= TREE_VIEW_VERTICAL_SEPARATOR;
1255
1256           /* Select the detail for drawing the cell.  relevant
1257            * factors are parity, sortedness, and whether to
1258            * display rules.
1259            */
1260
1261           /* FIXME when we have style properties, clean this up.
1262            */
1263
1264           if (tree_view->priv->has_rules)
1265             {
1266               if (flags & GTK_CELL_RENDERER_SORTED)
1267                 {
1268                   if (parity)
1269                     detail = "cell_odd_ruled_sorted";
1270                   else
1271                     detail = "cell_even_ruled_sorted";
1272                 }
1273               else
1274                 {
1275                   if (parity)
1276                     detail = "cell_odd_ruled";
1277                   else
1278                     detail = "cell_even_ruled";
1279                 }
1280             }
1281           else
1282             {
1283               if (flags & GTK_CELL_RENDERER_SORTED)
1284                 {
1285                   if (parity)
1286                     detail = "cell_odd_sorted";
1287                   else
1288                     detail = "cell_even_sorted";
1289                 }
1290               else
1291                 {
1292                   if (parity)
1293                     detail = "cell_odd";
1294                   else
1295                     detail = "cell_even";
1296                 }
1297             }
1298
1299           g_assert (detail);
1300
1301           /* Draw background */
1302           gtk_paint_flat_box (widget->style,
1303                               event->window,
1304                               (flags & GTK_CELL_RENDERER_SELECTED) ?
1305                               GTK_STATE_SELECTED : GTK_STATE_NORMAL,
1306                               GTK_SHADOW_NONE,
1307                               &event->area,
1308                               widget,
1309                               detail,
1310                               background_area.x,
1311                               background_area.y,
1312                               background_area.width,
1313                               background_area.height);
1314
1315           if (i == tree_view->priv->expander_column &&
1316               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1317             {
1318               gboolean visible;
1319
1320               cell_area.x += depth*tree_view->priv->tab_offset;
1321               cell_area.width -= depth*tree_view->priv->tab_offset;
1322
1323               /* If we have an expander column, the highlight underline
1324                * starts with that column, so that it indicates which
1325                * level of the tree we're dropping at.
1326                */
1327               highlight_x = cell_area.x;
1328
1329               g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
1330               if (visible)
1331                 gtk_cell_renderer_render (cell,
1332                                           event->window,
1333                                           widget,
1334                                           &background_area,
1335                                           &cell_area,
1336                                           &event->area,
1337                                           flags);
1338
1339               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
1340                 {
1341                   gint x, y;
1342                   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
1343                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1344                                             tree,
1345                                             node,
1346                                             x, y);
1347                 }
1348             }
1349           else
1350             {
1351               gboolean visible;
1352               g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
1353
1354               if (visible)
1355                 gtk_cell_renderer_render (cell,
1356                                           event->window,
1357                                           widget,
1358                                           &background_area,
1359                                           &cell_area,
1360                                           &event->area,
1361                                           flags);
1362             }
1363           cell_offset += column->displayed_width;
1364         }
1365
1366       if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
1367         gtk_tree_view_draw_focus (widget);
1368
1369       if (node == drag_highlight)
1370         {
1371           /* Draw indicator for the drop
1372            */
1373           gint highlight_y = -1;
1374           GtkRBTree *tree = NULL;
1375           GtkRBNode *node = NULL;
1376           gint width;
1377
1378           switch (tree_view->priv->drag_dest_pos)
1379             {
1380             case GTK_TREE_VIEW_DROP_BEFORE:
1381               highlight_y = background_area.y - TREE_VIEW_VERTICAL_SEPARATOR/2;
1382               break;
1383
1384             case GTK_TREE_VIEW_DROP_AFTER:
1385               highlight_y = background_area.y + background_area.height + TREE_VIEW_VERTICAL_SEPARATOR/2;
1386               break;
1387
1388             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1389             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1390               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
1391
1392               if (tree == NULL)
1393                 break;
1394               gdk_drawable_get_size (tree_view->priv->bin_window,
1395                                      &width, NULL);
1396               gtk_paint_focus (widget->style,
1397                                tree_view->priv->bin_window,
1398                                NULL,
1399                                widget,
1400                                "add-mode",
1401                                0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
1402                                width - 1, BACKGROUND_HEIGHT (node) - 1);
1403
1404               break;
1405             }
1406
1407           if (highlight_y >= 0)
1408             {
1409               gdk_draw_line (event->window,
1410                              widget->style->black_gc,
1411                              highlight_x,
1412                              highlight_y,
1413                              bin_window_width - highlight_x,
1414                              highlight_y);
1415             }
1416         }
1417
1418       y_offset += max_height;
1419       if (node->children)
1420         {
1421           GtkTreeIter parent = iter;
1422           gboolean has_child;
1423
1424           tree = node->children;
1425           node = tree->root;
1426
1427           g_assert (node != tree->nil);
1428
1429           while (node->left != tree->nil)
1430             node = node->left;
1431           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
1432                                                     &iter,
1433                                                     &parent);
1434           cell = gtk_tree_view_get_column (tree_view, 0)->cell;
1435           depth++;
1436
1437           /* Sanity Check! */
1438           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
1439         }
1440       else
1441         {
1442           gboolean done = FALSE;
1443           do
1444             {
1445               node = _gtk_rbtree_next (tree, node);
1446               if (node != NULL)
1447                 {
1448                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
1449                   cell = gtk_tree_view_get_column (tree_view, 0)->cell;
1450                   done = TRUE;
1451
1452                   /* Sanity Check! */
1453                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
1454                 }
1455               else
1456                 {
1457                   GtkTreeIter parent_iter = iter;
1458                   gboolean has_parent;
1459
1460                   node = tree->parent_node;
1461                   tree = tree->parent_tree;
1462                   if (tree == NULL)
1463                     /* we've run out of tree.  It's okay to return though, as
1464                      * we'd only break out of the while loop below. */
1465                     return TRUE;
1466                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
1467                                                            &iter,
1468                                                            &parent_iter);
1469                   depth--;
1470
1471                   /* Sanity check */
1472                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
1473                 }
1474             }
1475           while (!done);
1476         }
1477     }
1478   while (y_offset < event->area.height);
1479
1480   if (cursor_path)
1481     gtk_tree_path_free (cursor_path);
1482
1483   if (drag_dest_path)
1484     gtk_tree_path_free (drag_dest_path);
1485
1486   return TRUE;
1487 }
1488
1489 static gboolean
1490 gtk_tree_view_expose (GtkWidget      *widget,
1491                       GdkEventExpose *event)
1492 {
1493   GtkTreeView *tree_view;
1494
1495   g_return_val_if_fail (widget != NULL, FALSE);
1496   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1497
1498   tree_view = GTK_TREE_VIEW (widget);
1499
1500   if (event->window == tree_view->priv->bin_window)
1501     return gtk_tree_view_bin_expose (widget, event);
1502
1503   return TRUE;
1504 }
1505
1506 static gboolean
1507 coords_are_over_arrow (GtkTreeView *tree_view,
1508                        GtkRBTree   *tree,
1509                        GtkRBNode   *node,
1510                        /* these are in tree window coords */
1511                        gint         x,
1512                        gint         y)
1513 {
1514   GdkRectangle arrow;
1515   gint x2;
1516
1517   if (!GTK_WIDGET_REALIZED (tree_view))
1518     return FALSE;
1519
1520   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1521     return FALSE;
1522
1523   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
1524
1525   arrow.height = BACKGROUND_HEIGHT (node);
1526
1527   gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
1528
1529   arrow.width = x2 - arrow.x;
1530
1531   return (x >= arrow.x &&
1532           x < (arrow.x + arrow.height) &&
1533           y >= arrow.y &&
1534           y < (arrow.y + arrow.height));
1535 }
1536
1537 static void
1538 do_unprelight (GtkTreeView *tree_view,
1539                /* these are in tree window coords */
1540                gint x,
1541                gint y)
1542 {
1543   if (tree_view->priv->prelight_node == NULL)
1544     return;
1545
1546   GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1547
1548   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1549       !coords_are_over_arrow (tree_view,
1550                               tree_view->priv->prelight_tree,
1551                               tree_view->priv->prelight_node,
1552                               x,
1553                               y))
1554     /* We need to unprelight the old arrow. */
1555     {
1556       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1557
1558       gtk_tree_view_draw_arrow (tree_view,
1559                                 tree_view->priv->prelight_tree,
1560                                 tree_view->priv->prelight_node,
1561                                 x,
1562                                 y);
1563
1564     }
1565
1566   tree_view->priv->prelight_node = NULL;
1567   tree_view->priv->prelight_tree = NULL;
1568 }
1569
1570 static void
1571 do_prelight (GtkTreeView *tree_view,
1572              GtkRBTree   *tree,
1573              GtkRBNode   *node,
1574              /* these are in tree window coords */
1575              gint         x,
1576              gint         y)
1577 {
1578   if (coords_are_over_arrow (tree_view, tree, node, x, y))
1579     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1580
1581   tree_view->priv->prelight_node = node;
1582   tree_view->priv->prelight_tree = tree;
1583
1584   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1585 }
1586
1587 static void
1588 ensure_unprelighted (GtkTreeView *tree_view)
1589 {
1590   do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
1591 }
1592
1593 static gboolean
1594 gtk_tree_view_motion (GtkWidget      *widget,
1595                       GdkEventMotion *event)
1596 {
1597   GtkTreeView *tree_view;
1598   GtkRBTree *tree;
1599   GtkRBNode *node;
1600   gint new_y;
1601   GtkRBTree *old_prelight_tree;
1602   GtkRBNode *old_prelight_node;
1603
1604   tree_view = (GtkTreeView *) widget;
1605
1606   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1607     {
1608       gint x;
1609       gint new_width;
1610
1611       if (event->is_hint || event->window != widget->window)
1612         gtk_widget_get_pointer (widget, &x, NULL);
1613       else
1614         x = event->x;
1615
1616       new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos, &x);
1617       if (x != tree_view->priv->x_drag)
1618         {
1619           gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos), new_width);
1620         }
1621
1622       /* FIXME: Do we need to scroll */
1623       _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1624       return FALSE;
1625     }
1626
1627   /* Sanity check it */
1628   if (event->window != tree_view->priv->bin_window)
1629     return FALSE;
1630
1631   if (tree_view->priv->tree == NULL)
1632     return FALSE;
1633
1634   gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
1635
1636   old_prelight_tree = tree_view->priv->prelight_tree;
1637   old_prelight_node = tree_view->priv->prelight_node;
1638
1639   do_unprelight (tree_view, event->x, event->y);
1640
1641   new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1642
1643   _gtk_rbtree_find_offset (tree_view->priv->tree,
1644                            TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1645                            &tree,
1646                            &node);
1647
1648   if (tree == NULL)
1649     return TRUE;
1650
1651   /* If we are currently pressing down a button, we don't want to prelight anything else. */
1652   if ((tree_view->priv->button_pressed_node != NULL) &&
1653       (tree_view->priv->button_pressed_node != node))
1654     return TRUE;
1655
1656
1657   do_prelight (tree_view, tree, node, event->x, new_y);
1658
1659   if (old_prelight_node != tree_view->priv->prelight_node)
1660     {
1661       if (old_prelight_node)
1662         gtk_tree_view_queue_draw_node (tree_view,
1663                                        old_prelight_tree,
1664                                        old_prelight_node,
1665                                        NULL);
1666
1667       if (tree_view->priv->prelight_node)
1668         gtk_tree_view_queue_draw_node (tree_view,
1669                                        tree_view->priv->prelight_tree,
1670                                        tree_view->priv->prelight_node,
1671                                        NULL);
1672     }
1673
1674   return TRUE;
1675 }
1676
1677 /* FIXME Is this function necessary? Can I get an enter_notify event
1678  * w/o either an expose event or a mouse motion event?
1679  */
1680 static gboolean
1681 gtk_tree_view_enter_notify (GtkWidget        *widget,
1682                             GdkEventCrossing *event)
1683 {
1684   GtkTreeView *tree_view;
1685   GtkRBTree *tree;
1686   GtkRBNode *node;
1687   gint new_y;
1688
1689   g_return_val_if_fail (widget != NULL, FALSE);
1690   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1691
1692   tree_view = GTK_TREE_VIEW (widget);
1693
1694   /* Sanity check it */
1695   if (event->window != tree_view->priv->bin_window)
1696     return FALSE;
1697
1698   if (tree_view->priv->tree == NULL)
1699     return FALSE;
1700
1701   if ((tree_view->priv->button_pressed_node != NULL) &&
1702       (tree_view->priv->button_pressed_node != node))
1703     return TRUE;
1704
1705   /* find the node internally */
1706   new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1707
1708   _gtk_rbtree_find_offset (tree_view->priv->tree,
1709                            TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1710                            &tree,
1711                            &node);
1712
1713   if (node == NULL)
1714     return FALSE;
1715
1716   do_prelight (tree_view, tree, node, event->x, new_y);
1717
1718   if (tree_view->priv->prelight_node)
1719     gtk_tree_view_queue_draw_node (tree_view,
1720                                    tree_view->priv->prelight_tree,
1721                                    tree_view->priv->prelight_node,
1722                                    NULL);
1723
1724   return TRUE;
1725 }
1726
1727 static gboolean
1728 gtk_tree_view_leave_notify (GtkWidget        *widget,
1729                             GdkEventCrossing *event)
1730 {
1731   GtkTreeView *tree_view;
1732
1733   g_return_val_if_fail (widget != NULL, FALSE);
1734   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1735
1736   tree_view = GTK_TREE_VIEW (widget);
1737
1738   if (tree_view->priv->prelight_node)
1739     gtk_tree_view_queue_draw_node (tree_view,
1740                                    tree_view->priv->prelight_tree,
1741                                    tree_view->priv->prelight_node,
1742                                    NULL);
1743
1744   ensure_unprelighted (tree_view);
1745
1746   return TRUE;
1747 }
1748
1749 static gboolean
1750 gtk_tree_view_button_press (GtkWidget      *widget,
1751                             GdkEventButton *event)
1752 {
1753   GtkTreeView *tree_view;
1754   GList *list;
1755   GtkTreeViewColumn *column = NULL;
1756   gint i;
1757   GdkRectangle background_area;
1758   GdkRectangle cell_area;
1759
1760   g_return_val_if_fail (widget != NULL, FALSE);
1761   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1762   g_return_val_if_fail (event != NULL, FALSE);
1763
1764   tree_view = GTK_TREE_VIEW (widget);
1765
1766   if (event->window == tree_view->priv->bin_window)
1767     {
1768       GtkRBNode *node;
1769       GtkRBTree *tree;
1770       GtkTreePath *path;
1771       gchar *path_string;
1772       gint depth;
1773       gint new_y;
1774       gint y_offset;
1775       GtkTreeViewColumn *column = NULL;
1776
1777       if (!GTK_WIDGET_HAS_FOCUS (widget))
1778         gtk_widget_grab_focus (widget);
1779       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1780
1781       /* are we in an arrow? */
1782       if (tree_view->priv->prelight_node &&
1783           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1784         {
1785           if (event->button == 1)
1786             {
1787               gtk_grab_add (widget);
1788               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1789               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1790               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1791                                         tree_view->priv->prelight_tree,
1792                                         tree_view->priv->prelight_node,
1793                                         event->x,
1794                                         event->y);
1795             }
1796           return TRUE;
1797         }
1798
1799       /* find the node that was clicked */
1800       new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1801       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1802                                            TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1803                                            &tree,
1804                                            &node) + new_y - (gint)event->y;
1805
1806       if (node == NULL)
1807         /* We clicked in dead space */
1808         return TRUE;
1809
1810       /* Get the path and the node */
1811       path = _gtk_tree_view_find_path (tree_view, tree, node);
1812       depth = gtk_tree_path_get_depth (path);
1813       background_area.y = y_offset + event->y + TREE_VIEW_VERTICAL_SEPARATOR;
1814       background_area.height = GTK_RBNODE_GET_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPARATOR;
1815       background_area.x = 0;
1816       /* Let the cell have a chance at selecting it. */
1817
1818       for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1819         {
1820           GtkCellRenderer *cell;
1821           GtkTreeIter iter;
1822           gboolean visible;
1823           gboolean can_activate;
1824
1825           column = list->data;
1826
1827           if (!column->visible)
1828             continue;
1829
1830           background_area.width = column->displayed_width;
1831           if (i == tree_view->priv->expander_column &&
1832               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1833             {
1834               cell_area = background_area;
1835               cell_area.x += depth*tree_view->priv->tab_offset;
1836               cell_area.width -= depth*tree_view->priv->tab_offset;
1837             }
1838           else
1839             {
1840               cell_area = background_area;
1841             }
1842
1843           cell = column->cell;
1844
1845           if ((background_area.x > (gint) event->x) ||
1846               (background_area.y > (gint) event->y) ||
1847               (background_area.x + background_area.width <= (gint) event->x) ||
1848               (background_area.y + background_area.height <= (gint) event->y))
1849             {
1850               background_area.x += background_area.width;
1851               continue;
1852             }
1853
1854           gtk_tree_model_get_iter (tree_view->priv->model,
1855                                    &iter,
1856                                    path);
1857           gtk_tree_view_column_set_cell_data (column,
1858                                               tree_view->priv->model,
1859                                               &iter);
1860
1861           path_string = gtk_tree_path_to_string (path);
1862
1863           g_object_get (G_OBJECT (cell),
1864                         "visible", &visible,
1865                         "can_activate", &can_activate,
1866                         NULL);
1867           if (visible &&
1868               can_activate &&
1869               gtk_cell_renderer_event (cell, (GdkEvent *)event,
1870                                        widget, path_string,
1871                                        &background_area,
1872                                        &cell_area, 0))
1873             {
1874               g_free (path_string);
1875               gtk_tree_path_free (path);
1876               return TRUE;
1877             }
1878           else
1879             {
1880               g_free (path_string);
1881               break;
1882             }
1883         }
1884
1885       if (column == NULL)
1886         return FALSE;
1887
1888       /* Save press to possibly begin a drag
1889        */
1890       if (tree_view->priv->pressed_button < 0)
1891         {
1892           tree_view->priv->pressed_button = event->button;
1893           tree_view->priv->press_start_x = event->x;
1894           tree_view->priv->press_start_y = event->y;
1895         }
1896
1897       /* Handle the selection */
1898       if (tree_view->priv->selection == NULL)
1899         tree_view->priv->selection =
1900           _gtk_tree_selection_new_with_tree_view (tree_view);
1901
1902       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
1903                                                 node,
1904                                                 tree,
1905                                                 path,
1906                                                 event->state);
1907       gtk_tree_path_free (path);
1908
1909       if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1910         {
1911           gtk_tree_view_row_activated (tree_view, column );
1912         }
1913       return TRUE;
1914     }
1915
1916   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1917     {
1918       column = list->data;
1919       if (event->window == column->window &&
1920           column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE &&
1921           column->window)
1922         {
1923           gpointer drag_data;
1924
1925           if (gdk_pointer_grab (column->window, FALSE,
1926                                 GDK_POINTER_MOTION_HINT_MASK |
1927                                 GDK_BUTTON1_MOTION_MASK |
1928                                 GDK_BUTTON_RELEASE_MASK,
1929                                 NULL, NULL, event->time))
1930             return FALSE;
1931
1932           gtk_grab_add (widget);
1933           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1934
1935           /* block attached dnd signal handler */
1936           drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1937           if (drag_data)
1938             gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1939
1940           if (!GTK_WIDGET_HAS_FOCUS (widget))
1941             gtk_widget_grab_focus (widget);
1942
1943           tree_view->priv->drag_pos = i;
1944           tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1945         }
1946     }
1947   return TRUE;
1948 }
1949
1950 static gboolean
1951 gtk_tree_view_button_release (GtkWidget      *widget,
1952                               GdkEventButton *event)
1953 {
1954   GtkTreeView *tree_view;
1955
1956   g_return_val_if_fail (widget != NULL, FALSE);
1957   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1958   g_return_val_if_fail (event != NULL, FALSE);
1959
1960   tree_view = GTK_TREE_VIEW (widget);
1961
1962   if (tree_view->priv->pressed_button == event->button)
1963     tree_view->priv->pressed_button = -1;
1964
1965   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1966     {
1967       gpointer drag_data;
1968       gint width;
1969       gint x;
1970       gint i;
1971
1972       i = tree_view->priv->drag_pos;
1973       tree_view->priv->drag_pos = -1;
1974
1975       /* unblock attached dnd signal handler */
1976       drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1977       if (drag_data)
1978         gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1979
1980       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1981       gtk_widget_get_pointer (widget, &x, NULL);
1982       gtk_grab_remove (widget);
1983       gdk_pointer_ungrab (event->time);
1984
1985       width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1986       gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1987       return FALSE;
1988     }
1989
1990   if (tree_view->priv->button_pressed_node == NULL)
1991     return FALSE;
1992
1993   if (event->button == 1)
1994     {
1995       gtk_grab_remove (widget);
1996       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1997           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1998         {
1999           GtkTreePath *path;
2000           GtkTreeIter iter;
2001
2002           /* Actually activate the node */
2003           if (tree_view->priv->button_pressed_node->children == NULL)
2004             {
2005               GtkTreeIter child;
2006               path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
2007                                                tree_view->priv->button_pressed_tree,
2008                                                tree_view->priv->button_pressed_node);
2009               tree_view->priv->button_pressed_node->children = _gtk_rbtree_new ();
2010               tree_view->priv->button_pressed_node->children->parent_tree = tree_view->priv->button_pressed_tree;
2011               tree_view->priv->button_pressed_node->children->parent_node = tree_view->priv->button_pressed_node;
2012               gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2013
2014               if (gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter))
2015                 gtk_tree_view_build_tree (tree_view,
2016                                           tree_view->priv->button_pressed_node->children,
2017                                           &child,
2018                                           gtk_tree_path_get_depth (path) + 1,
2019                                           FALSE,
2020                                           GTK_WIDGET_REALIZED (widget));
2021             }
2022           else
2023             {
2024               path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
2025                                                tree_view->priv->button_pressed_node->children,
2026                                                tree_view->priv->button_pressed_node->children->root);
2027               gtk_tree_model_get_iter (tree_view->priv->model,
2028                                        &iter,
2029                                        path);
2030
2031               gtk_tree_view_discover_dirty (GTK_TREE_VIEW (widget),
2032                                             tree_view->priv->button_pressed_node->children,
2033                                             &iter,
2034                                             gtk_tree_path_get_depth (path));
2035               gtk_tree_view_unref_tree (GTK_TREE_VIEW (widget),
2036                                         tree_view->priv->button_pressed_node->children);
2037               _gtk_rbtree_remove (tree_view->priv->button_pressed_node->children);
2038             }
2039           gtk_tree_path_free (path);
2040
2041           _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2042         }
2043
2044       tree_view->priv->button_pressed_node = NULL;
2045     }
2046
2047   return TRUE;
2048 }
2049
2050 static void
2051 gtk_tree_view_set_focus_child (GtkContainer *container,
2052                                GtkWidget    *child)
2053 {
2054
2055 }
2056 static void
2057 gtk_tree_view_draw_focus (GtkWidget *widget)
2058 {
2059   GtkTreeView *tree_view;
2060   GtkTreePath *cursor_path;
2061   GtkRBTree *tree = NULL;
2062   GtkRBNode *node = NULL;
2063   gint x, y;
2064   gint width, height;
2065
2066   g_return_if_fail (widget != NULL);
2067   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2068
2069   tree_view = GTK_TREE_VIEW (widget);
2070
2071   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
2072     return;
2073
2074   if (tree_view->priv->cursor == NULL)
2075     return;
2076
2077   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2078   if (cursor_path == NULL)
2079     return;
2080
2081   _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
2082
2083   if (tree == NULL)
2084     {
2085       gtk_tree_path_free (cursor_path);
2086       return;
2087     }
2088
2089   gdk_drawable_get_size (tree_view->priv->bin_window,
2090                          &width, NULL);
2091
2092
2093   x = 0;
2094   y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2095   gdk_drawable_get_size (tree_view->priv->bin_window,
2096                          &width, NULL);
2097   width = width - 1;
2098   height = BACKGROUND_HEIGHT (node) - 1;
2099   if (tree_view->priv->focus_column != NULL)
2100     {
2101       GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data);
2102       gboolean visible;
2103       gboolean can_focus;
2104
2105       g_object_get (G_OBJECT (column->cell),
2106                     "can_activate", &can_focus,
2107                     "visible", &visible,
2108                     NULL);
2109       if (can_focus && visible)
2110         {
2111           GtkTreeIter iter;
2112           GdkRectangle cell_area;
2113           gint x_offset;
2114           gint y_offset;
2115
2116           cell_area.x = column->button->allocation.x;
2117           cell_area.y = y;
2118           cell_area.width = column->displayed_width;
2119           cell_area.height = CELL_HEIGHT (node);
2120
2121           gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
2122           gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, &iter);
2123
2124           gtk_cell_renderer_get_size (column->cell, GTK_WIDGET (tree_view), &cell_area, &x_offset, &y_offset, &width, &height);
2125           width += 2;
2126           height += 2;
2127           x = cell_area.x + x_offset - 1;
2128           y = cell_area.y + y_offset - 1 + TREE_VIEW_VERTICAL_SEPARATOR/2;
2129         }
2130     }
2131
2132   gtk_paint_focus (widget->style,
2133                    tree_view->priv->bin_window,
2134                    NULL,
2135                    widget,
2136                    "add-mode",
2137                    x, y, width, height);
2138
2139   gtk_tree_path_free (cursor_path);
2140 }
2141
2142
2143 static gint
2144 gtk_tree_view_focus_in (GtkWidget     *widget,
2145                         GdkEventFocus *event)
2146 {
2147   GtkTreeView *tree_view;
2148
2149   g_return_val_if_fail (widget != NULL, FALSE);
2150   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2151   g_return_val_if_fail (event != NULL, FALSE);
2152
2153   tree_view = GTK_TREE_VIEW (widget);
2154
2155   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2156
2157   /* FIXME don't redraw so much */
2158   gtk_widget_queue_draw (widget);
2159
2160   return FALSE;
2161 }
2162
2163
2164 static gint
2165 gtk_tree_view_focus_out (GtkWidget     *widget,
2166                          GdkEventFocus *event)
2167 {
2168   g_return_val_if_fail (widget != NULL, FALSE);
2169   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2170   g_return_val_if_fail (event != NULL, FALSE);
2171
2172   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2173
2174   /* FIXME don't redraw so much */
2175   gtk_widget_queue_draw (widget);
2176
2177   return FALSE;
2178 }
2179
2180 /* Returns TRUE if the focus is within the headers, after the focus operation is
2181  * done
2182  */
2183 static gboolean
2184 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
2185                             GtkDirectionType  dir)
2186 {
2187   GtkWidget *focus_child;
2188   GtkContainer *container;
2189
2190   GList *last_column, *first_column;
2191   GList *tmp_list;
2192
2193   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2194     return FALSE;
2195
2196   focus_child = GTK_CONTAINER (tree_view)->focus_child;
2197   container = GTK_CONTAINER (tree_view);
2198
2199   for (last_column = g_list_last (tree_view->priv->columns);
2200        last_column &&
2201          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2202          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2203        last_column = last_column->prev);
2204
2205   for (first_column = tree_view->priv->columns;
2206        first_column &&
2207          !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible) &&
2208          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button);
2209        first_column = first_column->next);
2210
2211   /* No headers are visible, or are focusable.  We can't focus in or out.
2212    */
2213   if (last_column == NULL)
2214     return FALSE;
2215
2216   switch (dir)
2217     {
2218     case GTK_DIR_TAB_BACKWARD:
2219     case GTK_DIR_TAB_FORWARD:
2220     case GTK_DIR_UP:
2221     case GTK_DIR_DOWN:
2222       if (focus_child == NULL)
2223         {
2224           if (tree_view->priv->focus_column != NULL)
2225             focus_child = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data)->button;
2226           else
2227             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
2228           gtk_widget_grab_focus (focus_child);
2229           break;
2230         }
2231       return FALSE;
2232
2233     case GTK_DIR_LEFT:
2234     case GTK_DIR_RIGHT:
2235       if (focus_child == NULL)
2236         {
2237           if (tree_view->priv->focus_column != NULL)
2238             focus_child = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data)->button;
2239           else if (dir == GTK_DIR_LEFT)
2240             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
2241           else
2242             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
2243           gtk_widget_grab_focus (focus_child);
2244           break;
2245         }
2246
2247       if (gtk_container_focus (GTK_CONTAINER (focus_child), dir))
2248         {
2249           /* The focus moves inside the button. */
2250           /* This is probably a great example of bad UI */
2251           break;
2252         }
2253
2254       /* We need to move the focus among the row of buttons. */
2255       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2256         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
2257           break;
2258
2259       if (tmp_list == first_column && dir == GTK_DIR_LEFT)
2260         {
2261           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
2262           gtk_widget_grab_focus (focus_child);
2263           break;
2264         }
2265       else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
2266         {
2267           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
2268           gtk_widget_grab_focus (focus_child);
2269           break;
2270         }
2271
2272       while (tmp_list)
2273         {
2274           GtkTreeViewColumn *column;
2275
2276           if (dir == GTK_DIR_RIGHT)
2277             tmp_list = tmp_list->next;
2278           else
2279             tmp_list = tmp_list->prev;
2280
2281           if (tmp_list == NULL)
2282             {
2283               g_warning ("Internal button not found");
2284               break;
2285             }
2286           column = tmp_list->data;
2287           if (column->button &&
2288               column->visible &&
2289               GTK_WIDGET_CAN_FOCUS (column->button))
2290             {
2291               focus_child = column->button;
2292               gtk_widget_grab_focus (column->button);
2293               break;
2294             }
2295         }
2296       break;
2297     default:
2298       g_assert_not_reached ();
2299       break;
2300     }
2301
2302   /* if focus child is non-null, we assume it's been set to the current focus child
2303    */
2304   if (focus_child)
2305     {
2306       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2307         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
2308           break;
2309
2310       tree_view->priv->focus_column = tmp_list;
2311
2312       /* If the following isn't true, then the view is smaller then the scrollpane.
2313        */
2314       if ((focus_child->allocation.x + focus_child->allocation.width) <=
2315           (tree_view->priv->hadjustment->upper))
2316         {
2317           /* Scroll to the button, if needed */
2318           if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
2319               (focus_child->allocation.x + focus_child->allocation.width))
2320             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2321                                       focus_child->allocation.x + focus_child->allocation.width -
2322                                       tree_view->priv->hadjustment->page_size);
2323           else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
2324             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2325                                       focus_child->allocation.x);
2326         }
2327     }
2328
2329   return (focus_child != NULL);
2330 }
2331
2332 /* WARNING: Somewhat scary function */
2333 /* We make the assumption that if container->focus_child != NULL, the focus must
2334  * be in the header.  For now, this is accurate.  It may not be in the future.
2335  */
2336 static gint
2337 gtk_tree_view_focus (GtkContainer     *container,
2338                      GtkDirectionType  direction)
2339 {
2340   GtkTreeView *tree_view;
2341   GtkWidget *focus_child;
2342   GdkEvent *event;
2343   GtkRBTree *cursor_tree;
2344   GtkRBNode *cursor_node;
2345   GtkTreePath *cursor_path;
2346
2347   g_return_val_if_fail (container != NULL, FALSE);
2348   g_return_val_if_fail (GTK_IS_TREE_VIEW (container), FALSE);
2349   g_return_val_if_fail (GTK_WIDGET_VISIBLE (container), FALSE);
2350
2351   tree_view = GTK_TREE_VIEW (container);
2352
2353   if (!GTK_WIDGET_IS_SENSITIVE (container))
2354     return FALSE;
2355
2356   focus_child = container->focus_child;
2357
2358   /* Case 1.  Headers have focus. */
2359   if (focus_child)
2360     {
2361       switch (direction)
2362         {
2363         case GTK_DIR_LEFT:
2364         case GTK_DIR_RIGHT:
2365           return (gtk_tree_view_header_focus (tree_view, direction));
2366         case GTK_DIR_TAB_BACKWARD:
2367         case GTK_DIR_UP:
2368           return FALSE;
2369         case GTK_DIR_TAB_FORWARD:
2370         case GTK_DIR_DOWN:
2371
2372           if (tree_view->priv->tree == NULL)
2373             return FALSE;
2374
2375           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2376           gtk_widget_grab_focus (GTK_WIDGET (container));
2377
2378           if (tree_view->priv->selection == NULL)
2379             tree_view->priv->selection =
2380               _gtk_tree_selection_new_with_tree_view (tree_view);
2381
2382           /* if there is no keyboard focus yet, we select the first node
2383            */
2384
2385           cursor_path = NULL;
2386
2387           if (tree_view->priv->cursor)
2388             cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2389
2390           if (cursor_path == NULL)
2391             {
2392               GtkTreePath *tmp_path = gtk_tree_path_new_root ();
2393
2394               if (tree_view->priv->cursor)
2395                 gtk_tree_row_reference_free (tree_view->priv->cursor);
2396
2397               tree_view->priv->cursor =
2398                 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
2399               cursor_path = tmp_path;
2400             }
2401
2402           gtk_tree_selection_select_path (tree_view->priv->selection,
2403                                           cursor_path);
2404
2405           gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2406
2407           gtk_tree_path_free (cursor_path);
2408
2409           return TRUE;
2410         }
2411     }
2412
2413   /* Case 2. We don't have focus at all. */
2414   if (!GTK_WIDGET_HAS_FOCUS (container))
2415     {
2416       if ((direction == GTK_DIR_TAB_FORWARD) ||
2417           (direction == GTK_DIR_RIGHT) ||
2418           (direction == GTK_DIR_DOWN) ||
2419           (direction == GTK_DIR_LEFT) ||
2420           (tree_view->priv->tree == NULL))
2421         return gtk_tree_view_header_focus (tree_view, direction);
2422
2423       /* The headers didn't want the focus, so we take it. */
2424       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2425       gtk_widget_grab_focus (GTK_WIDGET (container));
2426
2427       if (tree_view->priv->selection == NULL)
2428         tree_view->priv->selection =
2429           _gtk_tree_selection_new_with_tree_view (tree_view);
2430
2431       cursor_path = NULL;
2432       if (tree_view->priv->cursor)
2433         cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2434
2435       if (cursor_path == NULL)
2436         {
2437           GtkTreePath *tmp_path = gtk_tree_path_new_root ();
2438
2439           if (tree_view->priv->cursor)
2440             gtk_tree_row_reference_free (tree_view->priv->cursor);
2441
2442           tree_view->priv->cursor =
2443             gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
2444           cursor_path = tmp_path;
2445         }
2446
2447       gtk_tree_selection_select_path (tree_view->priv->selection,
2448                                       cursor_path);
2449
2450       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2451
2452       gtk_tree_path_free (cursor_path);
2453
2454       return TRUE;
2455     }
2456
2457   /* Case 3. We have focus already. */
2458   if (tree_view->priv->tree == NULL)
2459     return FALSE;
2460
2461   if (direction == GTK_DIR_TAB_BACKWARD)
2462     return (gtk_tree_view_header_focus (tree_view, direction));
2463   else if (direction == GTK_DIR_TAB_FORWARD)
2464     return FALSE;
2465
2466   cursor_path = NULL;
2467   if (tree_view->priv->cursor)
2468     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2469
2470   /* Do we have a focus path?  We should, unless it was deleted. */
2471   /* in that case, we pick the first one arbitrarily */
2472   if (cursor_path == NULL)
2473     {
2474       GtkTreePath *tmp_path = gtk_tree_path_new_root ();
2475
2476       if (tree_view->priv->cursor)
2477         gtk_tree_row_reference_free (tree_view->priv->cursor);
2478
2479       tree_view->priv->cursor =
2480         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
2481       cursor_path = tmp_path;
2482
2483       gtk_tree_selection_select_path (tree_view->priv->selection,
2484                                       cursor_path);
2485
2486       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2487
2488       gtk_tree_path_free (cursor_path);
2489
2490       return TRUE;
2491     }
2492
2493   /* Case 4. We have focus already.  Move the cursor. */
2494   if (direction == GTK_DIR_LEFT)
2495     {
2496       gfloat val;
2497       val = tree_view->priv->hadjustment->value - tree_view->priv->hadjustment->page_size/2;
2498       val = MAX (val, 0.0);
2499       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
2500       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2501
2502       gtk_tree_path_free (cursor_path);
2503
2504       return TRUE;
2505     }
2506   if (direction == GTK_DIR_RIGHT)
2507     {
2508       gfloat val;
2509       val = tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size/2;
2510       val = MIN (tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size, val);
2511       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
2512       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2513
2514       gtk_tree_path_free (cursor_path);
2515
2516       return TRUE;
2517     }
2518
2519   cursor_tree = NULL;
2520   cursor_node = NULL;
2521
2522   _gtk_tree_view_find_node (tree_view, cursor_path,
2523                             &cursor_tree,
2524                             &cursor_node);
2525
2526   /* undraw the old row */
2527   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2528
2529   gtk_tree_path_free (cursor_path);
2530   cursor_path = NULL;
2531
2532   if (tree_view->priv->cursor)
2533     {
2534       gtk_tree_row_reference_free (tree_view->priv->cursor);
2535       tree_view->priv->cursor = NULL;
2536     }
2537
2538   switch (direction)
2539     {
2540     case GTK_DIR_TAB_BACKWARD:
2541     case GTK_DIR_UP:
2542       _gtk_rbtree_prev_full (cursor_tree,
2543                              cursor_node,
2544                              &cursor_tree,
2545                              &cursor_node);
2546       break;
2547     case GTK_DIR_TAB_FORWARD:
2548     case GTK_DIR_DOWN:
2549       _gtk_rbtree_next_full (cursor_tree,
2550                              cursor_node,
2551                              &cursor_tree,
2552                              &cursor_node);
2553       break;
2554     default:
2555       break;
2556     }
2557
2558   if (cursor_node)
2559     {
2560       GdkModifierType state = 0;
2561
2562       event = gtk_get_current_event ();
2563       if (event)
2564         gdk_event_get_state (event, &state);
2565
2566       if (event)
2567         gdk_event_free (event);
2568
2569       cursor_path = _gtk_tree_view_find_path (tree_view,
2570                                               cursor_tree,
2571                                               cursor_node);
2572
2573       if (cursor_path)
2574         {
2575           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
2576                                                     cursor_node,
2577                                                     cursor_tree,
2578                                                     cursor_path,
2579                                                     state);
2580
2581           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
2582
2583
2584           /* draw the newly-selected row */
2585           gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2586
2587           gtk_tree_path_free (cursor_path);
2588         }
2589
2590       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
2591       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2592
2593       return TRUE;
2594     }
2595
2596   /* At this point, we've progressed beyond the edge of the rows. */
2597
2598   if (direction == GTK_DIR_UP)
2599     /* We can't go back anymore.  Try the headers */
2600     return (gtk_tree_view_header_focus (tree_view, direction));
2601
2602   /* we've reached the end of the tree.  Go on. */
2603   return FALSE;
2604 }
2605
2606 /* Container method
2607  */
2608 static void
2609 gtk_tree_view_remove (GtkContainer *container,
2610                       GtkWidget    *widget)
2611 {
2612   GtkTreeView *tree_view;
2613   GtkTreeViewChild *child = NULL;
2614   GList *tmp_list;
2615
2616   g_return_if_fail (container != NULL);
2617   g_return_if_fail (GTK_IS_TREE_VIEW (container));
2618
2619   tree_view = GTK_TREE_VIEW (container);
2620
2621   tmp_list = tree_view->priv->children;
2622   while (tmp_list)
2623     {
2624       child = tmp_list->data;
2625       if (child->widget == widget)
2626         {
2627           gtk_widget_unparent (widget);
2628
2629           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
2630           g_list_free_1 (tmp_list);
2631           g_free (child);
2632           return;
2633         }
2634
2635       tmp_list = tmp_list->next;
2636     }
2637
2638   tmp_list = tree_view->priv->columns;
2639
2640   while (tmp_list)
2641     {
2642       GtkTreeViewColumn *column;
2643       column = tmp_list->data;
2644       if (column->button == widget)
2645         {
2646           gtk_widget_unparent (widget);
2647           return;
2648         }
2649       tmp_list = tmp_list->next;
2650     }
2651
2652 }
2653
2654 static void
2655 gtk_tree_view_forall (GtkContainer *container,
2656                       gboolean      include_internals,
2657                       GtkCallback   callback,
2658                       gpointer      callback_data)
2659 {
2660   GtkTreeView *tree_view;
2661   GtkTreeViewChild *child = NULL;
2662   GtkTreeViewColumn *column;
2663   GList *tmp_list;
2664
2665   g_return_if_fail (container != NULL);
2666   g_return_if_fail (GTK_IS_TREE_VIEW (container));
2667   g_return_if_fail (callback != NULL);
2668
2669   tree_view = GTK_TREE_VIEW (container);
2670
2671   tmp_list = tree_view->priv->children;
2672   while (tmp_list)
2673     {
2674       child = tmp_list->data;
2675       tmp_list = tmp_list->next;
2676
2677       (* callback) (child->widget, callback_data);
2678     }
2679   if (include_internals == FALSE)
2680     return;
2681
2682   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2683     {
2684       column = tmp_list->data;
2685
2686       if (column->button)
2687         (* callback) (column->button, callback_data);
2688     }
2689 }
2690
2691 static void
2692 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
2693                              GtkTreeViewColumn *column)
2694 {
2695   g_return_if_fail (tree_view != NULL);
2696   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2697
2698   g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, column);
2699 }
2700
2701 /* TreeModel Callbacks
2702  */
2703
2704 static void
2705 gtk_tree_view_changed (GtkTreeModel *model,
2706                        GtkTreePath  *path,
2707                        GtkTreeIter  *iter,
2708                        gpointer      data)
2709 {
2710   GtkTreeView *tree_view = (GtkTreeView *)data;
2711   GtkRBTree *tree;
2712   GtkRBNode *node;
2713   gint height;
2714   gboolean dirty_marked;
2715   gboolean free_path = FALSE;
2716
2717   g_return_if_fail (path != NULL || iter != NULL);
2718
2719   if (path == NULL)
2720     {
2721       path = gtk_tree_model_get_path (model, iter);
2722       free_path = TRUE;
2723     }
2724   else if (iter == NULL)
2725     gtk_tree_model_get_iter (model, iter, path);
2726
2727   if (_gtk_tree_view_find_node (tree_view,
2728                                 path,
2729                                 &tree,
2730                                 &node))
2731     /* We aren't actually showing the node */
2732     goto done;
2733
2734   if (tree == NULL)
2735     goto done;
2736
2737   dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
2738                                                     iter,
2739                                                     gtk_tree_path_get_depth (path),
2740                                                     &height);
2741
2742   if (GTK_RBNODE_GET_HEIGHT (node) != height + TREE_VIEW_VERTICAL_SEPARATOR)
2743     {
2744       _gtk_rbtree_node_set_height (tree, node, height + TREE_VIEW_VERTICAL_SEPARATOR);
2745       gtk_widget_queue_resize (GTK_WIDGET (data));
2746       goto done;
2747     }
2748   if (dirty_marked)
2749     gtk_widget_queue_resize (GTK_WIDGET (data));
2750   else
2751     {
2752       gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
2753     }
2754
2755  done:
2756   if (free_path)
2757     gtk_tree_path_free (path);
2758 }
2759
2760 static void
2761 gtk_tree_view_inserted (GtkTreeModel *model,
2762                         GtkTreePath  *path,
2763                         GtkTreeIter  *iter,
2764                         gpointer      data)
2765 {
2766   GtkTreeView *tree_view = (GtkTreeView *) data;
2767   gint *indices;
2768   GtkRBTree *tmptree, *tree;
2769   GtkRBNode *tmpnode = NULL;
2770   gint max_height;
2771   gint depth;
2772   gint i = 0;
2773   gboolean free_path = FALSE;
2774
2775   if (tree_view->priv->tree == NULL)
2776     tree_view->priv->tree = _gtk_rbtree_new ();
2777
2778   tmptree = tree = tree_view->priv->tree;
2779   g_return_if_fail (path != NULL || iter != NULL);
2780
2781   if (path == NULL)
2782     {
2783       path = gtk_tree_model_get_path (model, iter);
2784       free_path = TRUE;
2785     }
2786   else if (iter == NULL)
2787     gtk_tree_model_get_iter (model, iter, path);
2788
2789   /* Update all row-references */
2790   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
2791
2792   depth = gtk_tree_path_get_depth (path);
2793   indices = gtk_tree_path_get_indices (path);
2794
2795   /* First, find the parent tree */
2796   while (i < depth - 1)
2797     {
2798       if (tmptree == NULL)
2799         {
2800           /* We aren't showing the node */
2801           goto done;
2802         }
2803
2804       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
2805       if (tmpnode == NULL)
2806         {
2807           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
2808                      "This possibly means that a GtkTreeModel inserted a child node\n" \
2809                      "before the parent was inserted.");
2810           goto done;
2811         }
2812       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
2813         {
2814           /* FIXME enforce correct behavior on model, probably */
2815           /* In theory, the model should have emitted has_child_toggled here.  We
2816            * try to catch it anyway, just to be safe, in case the model hasn't.
2817            */
2818           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
2819                                                            tree,
2820                                                            tmpnode);
2821           gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
2822           gtk_tree_path_free (tmppath);
2823           goto done;
2824         }
2825
2826       tmptree = tmpnode->children;
2827       tree = tmptree;
2828       i++;
2829     }
2830
2831   if (tree == NULL)
2832     goto done;
2833
2834   /* ref the node */
2835   gtk_tree_model_ref_node (tree_view->priv->model, iter);
2836   max_height = gtk_tree_view_insert_iter_height (tree_view,
2837                                                  tree,
2838                                                  iter,
2839                                                  depth);
2840   if (indices[depth - 1] == 0)
2841     {
2842       tmpnode = _gtk_rbtree_find_count (tree, 1);
2843       _gtk_rbtree_insert_before (tree, tmpnode, max_height);
2844     }
2845   else
2846     {
2847       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
2848       _gtk_rbtree_insert_after (tree, tmpnode, max_height);
2849     }
2850
2851   _gtk_tree_view_update_size (tree_view);
2852
2853  done:
2854   if (free_path)
2855     gtk_tree_path_free (path);
2856 }
2857
2858 static void
2859 gtk_tree_view_has_child_toggled (GtkTreeModel *model,
2860                                  GtkTreePath  *path,
2861                                  GtkTreeIter  *iter,
2862                                  gpointer      data)
2863 {
2864   GtkTreeView *tree_view = (GtkTreeView *)data;
2865   GtkTreeIter real_iter;
2866   gboolean has_child;
2867   GtkRBTree *tree;
2868   GtkRBNode *node;
2869   gboolean free_path = FALSE;
2870
2871   g_return_if_fail (path != NULL || iter != NULL);
2872
2873   if (iter)
2874     real_iter = *iter;
2875
2876   if (path == NULL)
2877     {
2878       path = gtk_tree_model_get_path (model, iter);
2879       free_path = TRUE;
2880     }
2881   else if (iter == NULL)
2882     gtk_tree_model_get_iter (model, &real_iter, path);
2883
2884   if (_gtk_tree_view_find_node (tree_view,
2885                                 path,
2886                                 &tree,
2887                                 &node))
2888     /* We aren't actually showing the node */
2889     goto done;
2890
2891   if (tree == NULL)
2892     goto done;
2893
2894   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
2895   /* Sanity check.
2896    */
2897   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
2898     goto done;
2899
2900   if (has_child)
2901     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
2902   else
2903     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
2904
2905   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
2906     {
2907       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2908       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
2909         {
2910           GList *list;
2911
2912           for (list = tree_view->priv->columns; list; list = list->next)
2913             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
2914               {
2915                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
2916                 break;
2917               }
2918         }
2919       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
2920     }
2921   else
2922     {
2923       /* FIXME: Just redraw the node */
2924       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2925     }
2926
2927  done:
2928   if (free_path)
2929     gtk_tree_path_free (path);
2930 }
2931
2932 static void
2933 gtk_tree_view_deleted (GtkTreeModel *model,
2934                        GtkTreePath  *path,
2935                        gpointer      data)
2936 {
2937   GtkTreeView *tree_view = (GtkTreeView *)data;
2938   GtkRBTree *tree;
2939   GtkRBNode *node;
2940   GList *list;
2941
2942   g_return_if_fail (path != NULL);
2943
2944   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
2945     return;
2946
2947   if (tree == NULL)
2948     return;
2949
2950   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
2951
2952   /* next, update the selection */
2953   if (tree_view->priv->anchor)
2954     {
2955       GtkTreePath *anchor_path;
2956
2957       /* the row reference may not have been updated yet. If it has not,
2958        * then anchor_path and path being equal indicates that the anchor
2959        * row was deleted. If it has, then anchor_path == NULL indicates the
2960        * the anchor row was deleted.
2961        */
2962
2963       anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2964
2965       if (anchor_path == NULL ||
2966           gtk_tree_path_compare (path, anchor_path) == 0)
2967         {
2968           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) &&
2969               tree_view->priv->selection)
2970             gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->selection),
2971                                      "selection_changed");
2972         }
2973
2974       if (anchor_path)
2975         gtk_tree_path_free (anchor_path);
2976     }
2977
2978   for (list = tree_view->priv->columns; list; list = list->next)
2979     if (((GtkTreeViewColumn *)list->data)->visible &&
2980         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2981       ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
2982
2983   /* Ensure we don't have a dangling pointer to a dead node */
2984   ensure_unprelighted (tree_view);
2985
2986   g_assert (tree_view->priv->prelight_node == NULL);
2987
2988   if (tree->root->count == 1)
2989     {
2990       if (tree_view->priv->tree == tree)
2991         tree_view->priv->tree = NULL;
2992
2993       _gtk_rbtree_remove (tree);
2994     }
2995   else
2996     {
2997       _gtk_rbtree_remove_node (tree, node);
2998     }
2999
3000   _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
3001 }
3002
3003 /* Internal tree functions */
3004 static gint
3005 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
3006                                   GtkRBTree   *tree,
3007                                   GtkTreeIter *iter,
3008                                   gint         depth)
3009 {
3010   GtkTreeViewColumn *column;
3011   GtkCellRenderer *cell;
3012   GList *list;
3013   gint max_height = 0;
3014   gint i;
3015
3016   i = 0;
3017
3018   /* do stuff with node */
3019   for (list = tree_view->priv->columns; list; list = list->next)
3020     {
3021       gint height = 0, width = 0;
3022       column = list->data;
3023
3024       if (!column->visible)
3025         continue;
3026
3027       if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
3028         {
3029           ++i;
3030           continue;
3031         }
3032
3033       cell = column->cell;
3034       gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
3035
3036       gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, &height);
3037       max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPARATOR + height);
3038
3039       if (i == tree_view->priv->expander_column &&
3040           TREE_VIEW_DRAW_EXPANDERS (tree_view))
3041         gtk_tree_view_column_set_width (column,
3042                                         MAX (column->width, depth * tree_view->priv->tab_offset + width));
3043       else
3044         gtk_tree_view_column_set_width (column,
3045                                         MAX (column->width, width));
3046
3047       ++i;
3048     }
3049   return max_height;
3050 }
3051
3052 static void
3053 gtk_tree_view_build_tree (GtkTreeView *tree_view,
3054                           GtkRBTree   *tree,
3055                           GtkTreeIter *iter,
3056                           gint         depth,
3057                           gboolean     recurse,
3058                           gboolean     calc_bounds)
3059 {
3060   GtkRBNode *temp = NULL;
3061   gint max_height;
3062
3063   do
3064     {
3065       max_height = 0;
3066       if (calc_bounds)
3067         max_height = gtk_tree_view_insert_iter_height (tree_view,
3068                                                        tree,
3069                                                        iter,
3070                                                        depth);
3071
3072       gtk_tree_model_ref_node (tree_view->priv->model, iter);
3073       temp = _gtk_rbtree_insert_after (tree, temp, max_height);
3074       if (recurse)
3075         {
3076           GtkTreeIter child;
3077
3078           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
3079             {
3080               temp->children = _gtk_rbtree_new ();
3081               temp->children->parent_tree = tree;
3082               temp->children->parent_node = temp;
3083               gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
3084             }
3085         }
3086       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
3087         {
3088           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
3089             temp->flags ^= GTK_RBNODE_IS_PARENT;
3090           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
3091         }
3092     }
3093   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
3094 }
3095
3096 static void
3097 gtk_tree_view_calc_size (GtkTreeView *tree_view,
3098                          GtkRBTree   *tree,
3099                          GtkTreeIter *iter,
3100                          gint         depth)
3101 {
3102   GtkRBNode *temp;
3103   GtkTreeIter child;
3104   GtkCellRenderer *cell;
3105   GList *list;
3106   GtkTreeViewColumn *column;
3107   gint max_height;
3108   gint i;
3109
3110   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
3111
3112   temp = tree->root;
3113   while (temp->left != tree->nil)
3114     temp = temp->left;
3115
3116   do
3117     {
3118       max_height = 0;
3119       /* Do stuff with node */
3120       for (list = tree_view->priv->columns, i = 0; i < tree_view->priv->n_columns; list = list->next, i++)
3121         {
3122           gint height = 0, width = 0;
3123           column = list->data;
3124
3125           if (!column->visible)
3126             continue;
3127
3128           gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
3129           cell = column->cell;
3130           gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, &height);
3131           max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPARATOR + height);
3132
3133           /* FIXME: I'm getting the width of all nodes here. )-: */
3134           if (column->dirty == FALSE)
3135             continue;
3136
3137           if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
3138             {
3139               continue;
3140             }
3141           if (i == tree_view->priv->expander_column &&
3142               TREE_VIEW_DRAW_EXPANDERS (tree_view))
3143             gtk_tree_view_column_set_width (column,
3144                                             MAX (column->width, depth * tree_view->priv->tab_offset + width));
3145           else
3146             gtk_tree_view_column_set_width (column, MAX (column->width, width));
3147         }
3148       _gtk_rbtree_node_set_height (tree, temp, max_height);
3149       if (temp->children != NULL &&
3150           gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
3151         gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
3152       temp = _gtk_rbtree_next (tree, temp);
3153     }
3154   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
3155 }
3156
3157 static gboolean
3158 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
3159                                    GtkTreeIter *iter,
3160                                    gint         depth,
3161                                    gint        *height)
3162 {
3163   GtkCellRenderer *cell;
3164   GtkTreeViewColumn *column;
3165   GList *list;
3166   gint i;
3167   gint retval = FALSE;
3168   gint tmpheight;
3169
3170   if (height)
3171     *height = 0;
3172
3173   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3174     {
3175       gint width;
3176       column = list->data;
3177       if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
3178         continue;
3179       if (!column->visible)
3180         continue;
3181
3182       cell = column->cell;
3183       gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
3184
3185       if (height)
3186         {
3187           gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, &tmpheight);
3188           *height = MAX (*height, tmpheight);
3189         }
3190       else
3191         {
3192           gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, NULL);
3193         }
3194       if (i == tree_view->priv->expander_column &&
3195           TREE_VIEW_DRAW_EXPANDERS (tree_view))
3196         {
3197           if (depth * tree_view->priv->tab_offset + width > column->width)
3198             {
3199               column->dirty = TRUE;
3200               retval = TRUE;
3201             }
3202         }
3203       else
3204         {
3205           if (width > column->width)
3206             {
3207               column->dirty = TRUE;
3208               retval = TRUE;
3209             }
3210         }
3211     }
3212
3213   return retval;
3214 }
3215
3216 static void
3217 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
3218                               GtkRBTree   *tree,
3219                               GtkTreeIter *iter,
3220                               gint         depth)
3221 {
3222   GtkRBNode *temp = tree->root;
3223   GtkTreeViewColumn *column;
3224   GList *list;
3225   GtkTreeIter child;
3226   gboolean is_all_dirty;
3227
3228   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
3229
3230   while (temp->left != tree->nil)
3231     temp = temp->left;
3232
3233   do
3234     {
3235       is_all_dirty = TRUE;
3236       for (list = tree_view->priv->columns; list; list = list->next)
3237         {
3238           column = list->data;
3239           if (column->dirty == FALSE)
3240             {
3241               is_all_dirty = FALSE;
3242               break;
3243             }
3244         }
3245
3246       if (is_all_dirty)
3247         return;
3248
3249       gtk_tree_view_discover_dirty_iter (tree_view,
3250                                          iter,
3251                                          depth,
3252                                          FALSE);
3253       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
3254           temp->children != NULL)
3255         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
3256       temp = _gtk_rbtree_next (tree, temp);
3257     }
3258   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
3259 }
3260
3261
3262 static void
3263 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
3264 {
3265   GtkTreePath *path;
3266   gboolean dirty = FALSE;
3267   GList *list;
3268   GtkTreeViewColumn *column;
3269   GtkTreeIter iter;
3270
3271   if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
3272       tree_view->priv->model)
3273     gtk_tree_view_setup_model (tree_view);
3274
3275   for (list = tree_view->priv->columns; list; list = list->next)
3276     {
3277       column = list->data;
3278       if (column->dirty)
3279         {
3280           dirty = TRUE;
3281           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3282             {
3283               gint w = 1;
3284
3285               if (column->button)
3286                 w = MAX (w, column->button->requisition.width);
3287
3288               gtk_tree_view_column_set_width (column, w);
3289             }
3290         }
3291     }
3292
3293   if (dirty == FALSE)
3294     return;
3295
3296   if (tree_view->priv->model == NULL)
3297     return;
3298
3299   path = gtk_tree_path_new_root ();
3300   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
3301     {
3302       gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
3303       _gtk_tree_view_update_size (tree_view);
3304     }
3305
3306   gtk_tree_path_free (path);
3307
3308   for (list = tree_view->priv->columns; list; list = list->next)
3309     {
3310       column = list->data;
3311       column->dirty = FALSE;
3312     }
3313 }
3314 #if 0
3315 static void
3316 gtk_tree_view_create_buttons (GtkTreeView *tree_view)
3317 {
3318   GtkWidget *alignment;
3319   GtkWidget *label;
3320   GList *list;
3321   GtkTreeViewColumn *column;
3322   gint i;
3323   GtkWidget *hbox;
3324   GtkWidget *arrow;
3325
3326   /* FIXME this has to be merged with update_button_contents() in
3327    * gtktreeviewcolumn.c
3328    */
3329
3330   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
3331     {
3332       column = list->data;
3333
3334       if (column->button != NULL)
3335         continue;
3336
3337       gtk_tree_view_create_button (tree_view, i);
3338       alignment = gtk_alignment_new (column->xalign, 0.5, 0.0, 0.0);
3339
3340       hbox = gtk_hbox_new (FALSE, 2);
3341       arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
3342
3343       column->arrow = arrow;
3344       column->alignment = alignment;
3345
3346       if (column->child)
3347         label = column->child;
3348       else
3349         {
3350           label = gtk_label_new (column->title);
3351           gtk_widget_show (label);
3352         }
3353
3354       if (column->xalign <= 0.5)
3355         gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
3356       else
3357         gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
3358
3359       gtk_box_pack_start (GTK_BOX (hbox), alignment, TRUE, TRUE, 0);
3360
3361       gtk_container_add (GTK_CONTAINER (alignment), label);
3362       gtk_container_add (GTK_CONTAINER (column->button), hbox);
3363
3364       gtk_widget_show (hbox);
3365       gtk_widget_show (alignment);
3366       /* don't show the arrow yet */
3367     }
3368
3369   gtk_tree_view_size_request_buttons (tree_view);
3370
3371   if (GTK_WIDGET_REALIZED (tree_view))
3372     gtk_tree_view_realize_buttons (tree_view);
3373
3374   if (GTK_WIDGET_MAPPED (tree_view))
3375     gtk_tree_view_map_buttons (tree_view);
3376 }
3377 #endif
3378
3379 /* Make sure the node is visible vertically */
3380 static void
3381 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
3382                                   GtkRBTree   *tree,
3383                                   GtkRBNode   *node)
3384 {
3385   gint offset;
3386
3387   offset = _gtk_rbtree_node_find_offset (tree, node);
3388
3389   /* we reverse the order, b/c in the unusual case of the
3390    * node's height being taller then the visible area, we'd rather
3391    * have the node flush to the top
3392    */
3393   if (offset + GTK_RBNODE_GET_HEIGHT (node) >
3394       tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
3395     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
3396                               offset + GTK_RBNODE_GET_HEIGHT (node) -
3397                               tree_view->priv->vadjustment->page_size);
3398   if (offset < tree_view->priv->vadjustment->value)
3399     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
3400                               offset);
3401 }
3402
3403 /* This function could be more efficient.
3404  * I'll optimize it if profiling seems to imply that
3405  * it's important
3406  */
3407 GtkTreePath *
3408 _gtk_tree_view_find_path (GtkTreeView *tree_view,
3409                           GtkRBTree   *tree,
3410                           GtkRBNode   *node)
3411 {
3412   GtkTreePath *path;
3413   GtkRBTree *tmp_tree;
3414   GtkRBNode *tmp_node, *last;
3415   gint count;
3416
3417   path = gtk_tree_path_new ();
3418
3419   g_return_val_if_fail (node != NULL, path);
3420   g_return_val_if_fail (node != tree->nil, path);
3421
3422   count = 1 + node->left->count;
3423
3424   last = node;
3425   tmp_node = node->parent;
3426   tmp_tree = tree;
3427   while (tmp_tree)
3428     {
3429       while (tmp_node != tmp_tree->nil)
3430         {
3431           if (tmp_node->right == last)
3432             count += 1 + tmp_node->left->count;
3433           last = tmp_node;
3434           tmp_node = tmp_node->parent;
3435         }
3436       gtk_tree_path_prepend_index (path, count - 1);
3437       last = tmp_tree->parent_node;
3438       tmp_tree = tmp_tree->parent_tree;
3439       if (last)
3440         {
3441           count = 1 + last->left->count;
3442           tmp_node = last->parent;
3443         }
3444     }
3445   return path;
3446 }
3447
3448 /* Returns TRUE if we ran out of tree before finding the node,
3449  * so the returned node is the last node we saw and the returned
3450  * tree is NULL
3451  */
3452 gboolean
3453 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
3454                           GtkTreePath  *path,
3455                           GtkRBTree   **tree,
3456                           GtkRBNode   **node)
3457 {
3458   GtkRBNode *tmpnode = NULL;
3459   GtkRBTree *tmptree = tree_view->priv->tree;
3460   gint *indices = gtk_tree_path_get_indices (path);
3461   gint depth = gtk_tree_path_get_depth (path);
3462   gint i = 0;
3463
3464   *node = NULL;
3465   *tree = NULL;
3466
3467   do
3468     {
3469       if (tmptree == NULL)
3470         {
3471           *node = tmpnode;
3472           *tree = tmptree;
3473           return TRUE;
3474         }
3475       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
3476       ++i;
3477       if (i >= depth)
3478         {
3479           *node = tmpnode;
3480           *tree = tmptree;
3481           return FALSE;
3482         }
3483       tmptree = tmpnode->children;
3484     }
3485   while (1);
3486 }
3487
3488 static void
3489 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
3490                                  GtkTreeIter  *iter,
3491                                  GtkRBTree    *tree,
3492                                  GtkRBNode    *node)
3493 {
3494   do
3495     {
3496       g_return_if_fail (node != NULL);
3497
3498       if (node->children)
3499         {
3500           GtkTreeIter child;
3501           GtkRBTree *new_tree;
3502           GtkRBNode *new_node;
3503
3504           new_tree = node->children;
3505           new_node = new_tree->root;
3506
3507           while (new_node && new_node->left != new_tree->nil)
3508             new_node = new_node->left;
3509
3510           g_return_if_fail (gtk_tree_model_iter_children (model, &child, iter));
3511           gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
3512         }
3513
3514       gtk_tree_model_unref_node (model, iter);
3515       node = _gtk_rbtree_next (tree, node);
3516     }
3517   while (gtk_tree_model_iter_next (model, iter));
3518 }
3519
3520 static void
3521 gtk_tree_view_unref_tree (GtkTreeView *tree_view,
3522                           GtkRBTree   *tree)
3523 {
3524   GtkTreeIter iter;
3525   GtkTreePath *path;
3526   GtkRBNode *node;
3527
3528   node = tree->root;
3529   while (node && node->left != tree->nil)
3530     node = node->left;
3531
3532   g_return_if_fail (node != NULL);
3533   path = _gtk_tree_view_find_path (tree_view, tree, node);
3534   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
3535                            &iter, path);
3536   gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
3537   gtk_tree_path_free (path);
3538 }
3539
3540 static void
3541 gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
3542                                GtkRBTree    *tree,
3543                                GtkRBNode    *node,
3544                                GdkRectangle *clip_rect)
3545 {
3546   GdkRectangle rect;
3547
3548   if (!GTK_WIDGET_REALIZED (tree_view))
3549     return;
3550
3551   rect.x = 0;
3552   rect.width = tree_view->priv->width;
3553
3554   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3555   rect.height = BACKGROUND_HEIGHT (node);
3556
3557   if (clip_rect)
3558     {
3559       GdkRectangle new_rect;
3560
3561       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
3562
3563       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
3564     }
3565   else
3566     {
3567       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
3568     }
3569 }
3570
3571 static void
3572 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
3573                                GtkTreePath      *path,
3574                                GdkRectangle     *clip_rect)
3575 {
3576   GtkRBTree *tree = NULL;
3577   GtkRBNode *node = NULL;
3578
3579   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3580
3581   if (tree)
3582     gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
3583 }
3584
3585 /* x and y are the mouse position
3586  */
3587 static void
3588 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
3589                           GtkRBTree   *tree,
3590                           GtkRBNode   *node,
3591                           gint         x,
3592                           gint         y)
3593 {
3594   GdkRectangle area;
3595   GtkStateType state;
3596   GtkWidget *widget;
3597   gint x_offset = 0;
3598
3599   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
3600     return;
3601
3602   widget = GTK_WIDGET (tree_view);
3603
3604   gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
3605
3606   area.x = x_offset;
3607   area.y = CELL_FIRST_PIXEL (tree_view, tree, node);
3608   area.width = tree_view->priv->tab_offset - 2;
3609   area.height = CELL_HEIGHT (node);
3610
3611   if (node == tree_view->priv->button_pressed_node)
3612     {
3613       if (x >= area.x && x <= (area.x + area.width) &&
3614           y >= area.y && y <= (area.y + area.height))
3615         state = GTK_STATE_ACTIVE;
3616       else
3617         state = GTK_STATE_NORMAL;
3618     }
3619   else
3620     {
3621       if (node == tree_view->priv->prelight_node &&
3622           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3623         state = GTK_STATE_PRELIGHT;
3624       else
3625         state = GTK_STATE_NORMAL;
3626     }
3627
3628   /* FIXME expander size should come from a style property */
3629 #define EXPANDER_SIZE 8
3630   gtk_paint_expander (widget->style,
3631                       tree_view->priv->bin_window,
3632                       state,
3633                       &area,
3634                       widget,
3635                       "treeview",
3636                       area.x,
3637                       (area.y + (area.height - EXPANDER_SIZE) / 2 - (area.height + 1) % 2),
3638                       node->children != NULL);
3639 #undef EXPANDER_SIZE
3640 }
3641
3642
3643 static void
3644 _gtk_tree_view_update_col_width (GtkTreeView *tree_view)
3645 {
3646   GList *list, *last_column;
3647   GtkTreeViewColumn *column;
3648   gint width = 0;
3649
3650   for (last_column = g_list_last (tree_view->priv->columns);
3651        last_column &&
3652          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
3653          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
3654        last_column = last_column->prev)
3655     ;
3656
3657   if (last_column == NULL)
3658     return;
3659
3660   for (list = tree_view->priv->columns; list != last_column; list = list->next)
3661     {
3662       column = GTK_TREE_VIEW_COLUMN (list->data);
3663       if (! column->visible)
3664         continue;
3665
3666       width += column->width;
3667       column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
3668     }
3669   column = GTK_TREE_VIEW_COLUMN (last_column->data);
3670   column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
3671 }
3672
3673 void
3674 _gtk_tree_view_update_size (GtkTreeView *tree_view)
3675 {
3676   gint width, height;
3677   GList *list;
3678   GtkTreeViewColumn *column;
3679   gint i;
3680
3681   if (tree_view->priv->model == NULL)
3682     {
3683       tree_view->priv->width = 0;
3684       tree_view->priv->height = 0;
3685       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3686       return;
3687     }
3688
3689   width = 0;
3690   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
3691     {
3692       column = list->data;
3693       if (!column->visible)
3694         continue;
3695       width += TREE_VIEW_COLUMN_WIDTH (column);
3696     }
3697
3698   if (tree_view->priv->tree == NULL)
3699     height = 0;
3700   else
3701     height = tree_view->priv->tree->root->offset + TREE_VIEW_VERTICAL_SEPARATOR;
3702
3703   if (tree_view->priv->width != width)
3704     {
3705       tree_view->priv->width = width;
3706       tree_view->priv->hadjustment->upper = width;
3707       gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
3708     }
3709
3710   if (tree_view->priv->height != height)
3711     {
3712       tree_view->priv->height = height;
3713       tree_view->priv->vadjustment->upper = tree_view->priv->height;
3714       gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
3715     }
3716
3717   if (GTK_WIDGET_REALIZED (tree_view))
3718     {
3719       gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
3720       gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
3721
3722       _gtk_tree_view_update_col_width (tree_view);
3723     }
3724
3725   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3726 }
3727
3728 /* this function returns the new width of the column being resized given
3729  * the column and x position of the cursor; the x cursor position is passed
3730  * in as a pointer and automagicly corrected if it's beyond min/max limits
3731  */
3732 static gint
3733 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
3734                                 gint       i,
3735                                 gint      *x)
3736 {
3737   GtkTreeViewColumn *column;
3738   gint width;
3739
3740   /* first translate the x position from widget->window
3741    * to clist->clist_window
3742    */
3743
3744   column = g_list_nth (tree_view->priv->columns, i)->data;
3745   width = *x - column->button->allocation.x;
3746
3747   /* Clamp down the value */
3748   if (column->min_width == -1)
3749     width = MAX (column->button->requisition.width,
3750                  width);
3751   else
3752     width = MAX (column->min_width,
3753                  width);
3754   if (column->max_width != -1)
3755     width = MIN (width, column->max_width != -1);
3756   *x = column->button->allocation.x + width;
3757
3758   return width;
3759 }
3760
3761 /* Callbacks */
3762 static void
3763 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
3764                                   GtkTreeView     *tree_view)
3765 {
3766   if (GTK_WIDGET_REALIZED (tree_view))
3767     {
3768       gdk_window_move (tree_view->priv->bin_window,
3769                        - tree_view->priv->hadjustment->value,
3770                        - tree_view->priv->vadjustment->value);
3771       gdk_window_move (tree_view->priv->header_window,
3772                        - tree_view->priv->hadjustment->value,
3773                        0);
3774
3775       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
3776       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
3777     }
3778 }
3779
3780 \f
3781
3782 /* Public methods
3783  */
3784
3785 /**
3786  * gtk_tree_view_new:
3787  *
3788  * Creates a new #GtkTreeView widget.
3789  *
3790  * Return value: A newly created #GtkTreeView widget.
3791  **/
3792 GtkWidget *
3793 gtk_tree_view_new (void)
3794 {
3795   GtkTreeView *tree_view;
3796
3797   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
3798
3799   return GTK_WIDGET (tree_view);
3800 }
3801
3802 /**
3803  * gtk_tree_view_new_with_model:
3804  * @model: the model.
3805  *
3806  * Creates a new #GtkTreeView widget with the model initialized to @model.
3807  *
3808  * Return value: A newly created #GtkTreeView widget.
3809  **/
3810 GtkWidget *
3811 gtk_tree_view_new_with_model (GtkTreeModel *model)
3812 {
3813   GtkTreeView *tree_view;
3814
3815   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
3816   gtk_tree_view_set_model (tree_view, model);
3817
3818   return GTK_WIDGET (tree_view);
3819 }
3820
3821 /**
3822  * gtk_tree_view_get_model:
3823  * @tree_view: a #GtkTreeView
3824  *
3825  * Returns the model the the #GtkTreeView is based on.  Returns NULL if the
3826  * model is unset.
3827  *
3828  * Return value: A #GtkTreeModel, or NULL if none is currently being used.
3829  **/
3830 GtkTreeModel *
3831 gtk_tree_view_get_model (GtkTreeView *tree_view)
3832 {
3833   g_return_val_if_fail (tree_view != NULL, NULL);
3834   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3835
3836   return tree_view->priv->model;
3837 }
3838
3839 static void
3840 gtk_tree_view_setup_model (GtkTreeView *tree_view)
3841 {
3842   GtkTreePath *path;
3843   GtkTreeIter iter;
3844
3845   tree_view->priv->tree = NULL;
3846
3847   g_signal_connectc (tree_view->priv->model,
3848                      "changed",
3849                      gtk_tree_view_changed,
3850                      tree_view,
3851                      FALSE);
3852   g_signal_connectc (tree_view->priv->model,
3853                      "inserted",
3854                      gtk_tree_view_inserted,
3855                      tree_view,
3856                      FALSE);
3857   g_signal_connectc (tree_view->priv->model,
3858                      "has_child_toggled",
3859                      gtk_tree_view_has_child_toggled,
3860                      tree_view,
3861                      FALSE);
3862   g_signal_connectc (tree_view->priv->model,
3863                      "deleted",
3864                      gtk_tree_view_deleted,
3865                      tree_view,
3866                      FALSE);
3867
3868   if (tree_view->priv->columns == NULL)
3869     return;
3870
3871   path = gtk_tree_path_new_root ();
3872
3873   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
3874     {
3875       tree_view->priv->tree = _gtk_rbtree_new ();
3876       gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
3877     }
3878
3879   gtk_tree_path_free (path);
3880
3881   //  gtk_tree_view_create_buttons (tree_view);
3882
3883   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3884 }
3885
3886 /**
3887  * gtk_tree_view_set_model:
3888  * @tree_view: A #GtkTreeNode.
3889  * @model: The model.
3890  *
3891  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
3892  * set, it will remove it before setting the new model.  If @model is NULL, then
3893  * it will unset the old model.
3894  **/
3895 void
3896 gtk_tree_view_set_model (GtkTreeView  *tree_view,
3897                          GtkTreeModel *model)
3898 {
3899   g_return_if_fail (tree_view != NULL);
3900   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3901
3902   if (model != NULL)
3903     g_object_ref (model);
3904
3905   if (tree_view->priv->model != NULL)
3906     {
3907       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
3908         {
3909           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3910                                                 G_SIGNAL_MATCH_FUNC,
3911                                                 0, 0, NULL,
3912                                                 gtk_tree_view_changed, NULL);
3913           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3914                                                 G_SIGNAL_MATCH_FUNC,
3915                                                 0, 0, NULL,
3916                                                 gtk_tree_view_inserted, NULL);
3917           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3918                                                 G_SIGNAL_MATCH_FUNC,
3919                                                 0, 0, NULL,
3920                                                 gtk_tree_view_has_child_toggled, NULL);
3921           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3922                                                 G_SIGNAL_MATCH_FUNC,
3923                                                 0, 0, NULL,
3924                                                 gtk_tree_view_deleted, NULL);
3925           _gtk_rbtree_free (tree_view->priv->tree);
3926         }
3927
3928       if (tree_view->priv->drag_dest_row)
3929         gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
3930
3931       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3932       g_object_unref (tree_view->priv->model);
3933     }
3934
3935   tree_view->priv->model = model;
3936
3937   if (model == NULL)
3938     {
3939       tree_view->priv->tree = NULL;
3940       if (GTK_WIDGET_REALIZED (tree_view))
3941         _gtk_tree_view_update_size (tree_view);
3942       return;
3943     }
3944   else if (GTK_WIDGET_REALIZED (tree_view))
3945     {
3946       gtk_tree_view_setup_model (tree_view);
3947       _gtk_tree_view_update_size (tree_view);
3948     }
3949
3950   g_object_notify (G_OBJECT (tree_view), "model");
3951 }
3952
3953 /**
3954  * gtk_tree_view_get_selection:
3955  * @tree_view: A #GtkTreeView.
3956  *
3957  * Gets the #GtkTreeSelection associated with @tree_view.
3958  *
3959  * Return value: A #GtkTreeSelection object.
3960  **/
3961 GtkTreeSelection *
3962 gtk_tree_view_get_selection (GtkTreeView *tree_view)
3963 {
3964   g_return_val_if_fail (tree_view != NULL, NULL);
3965   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3966
3967   if (tree_view->priv->selection == NULL)
3968     tree_view->priv->selection =
3969       _gtk_tree_selection_new_with_tree_view (tree_view);
3970
3971   return tree_view->priv->selection;
3972 }
3973
3974 /**
3975  * gtk_tree_view_get_hadjustment:
3976  * @tree_view: A #GtkTreeView
3977  *
3978  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
3979  *
3980  * Return value: A #GtkAdjustment object, or NULL if none is currently being
3981  * used.
3982  **/
3983 GtkAdjustment *
3984 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
3985 {
3986   g_return_val_if_fail (tree_view != NULL, NULL);
3987   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3988
3989   if (tree_view->priv->hadjustment == NULL)
3990     gtk_tree_view_set_hadjustment (tree_view, NULL);
3991
3992   return tree_view->priv->hadjustment;
3993 }
3994
3995 /**
3996  * gtk_tree_view_set_hadjustment:
3997  * @tree_view: A #GtkTreeView
3998  * @adjustment: The #GtkAdjustment to set, or NULL
3999  *
4000  * Sets the #GtkAdjustment for the current horizontal aspect.
4001  **/
4002 void
4003 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
4004                                GtkAdjustment *adjustment)
4005 {
4006   g_return_if_fail (tree_view != NULL);
4007   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4008
4009   gtk_tree_view_set_adjustments (tree_view,
4010                                  adjustment,
4011                                  tree_view->priv->vadjustment);
4012
4013   g_object_notify (G_OBJECT (tree_view), "hadjustment");
4014 }
4015
4016 /**
4017  * gtk_tree_view_get_vadjustment:
4018  * @tree_view: A #GtkTreeView
4019  *
4020  * Gets the #GtkAdjustment currently being used for the vertical aspect.
4021  *
4022  * Return value: A #GtkAdjustment object, or NULL if none is currently being
4023  * used.
4024  **/
4025 GtkAdjustment *
4026 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
4027 {
4028   g_return_val_if_fail (tree_view != NULL, NULL);
4029   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
4030
4031   if (tree_view->priv->vadjustment == NULL)
4032     gtk_tree_view_set_vadjustment (tree_view, NULL);
4033
4034   return tree_view->priv->vadjustment;
4035 }
4036
4037 /**
4038  * gtk_tree_view_set_vadjustment:
4039  * @tree_view: A #GtkTreeView
4040  * @adjustment: The #GtkAdjustment to set, or NULL
4041  *
4042  * Sets the #GtkAdjustment for the current vertical aspect.
4043  **/
4044 void
4045 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
4046                                GtkAdjustment *adjustment)
4047 {
4048   g_return_if_fail (tree_view != NULL);
4049   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4050
4051   gtk_tree_view_set_adjustments (tree_view,
4052                                  tree_view->priv->hadjustment,
4053                                  adjustment);
4054
4055   g_object_notify (G_OBJECT (tree_view), "vadjustment");
4056 }
4057
4058 /**
4059  * gtk_tree_view_set_adjustments:
4060  * @tree_view: A #GtkTreeView
4061  * @hadj: The horizontal #GtkAdjustment to set, or NULL
4062  * @vadj: The vertical #GtkAdjustment to set, or NULL
4063  *
4064  * Sets the horizonal and or vertical #GtkAdjustment.
4065  **/
4066 static void
4067 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
4068                                GtkAdjustment *hadj,
4069                                GtkAdjustment *vadj)
4070 {
4071   gboolean need_adjust = FALSE;
4072
4073   g_return_if_fail (tree_view != NULL);
4074   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4075
4076   if (hadj)
4077     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4078   else
4079     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4080   if (vadj)
4081     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4082   else
4083     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4084
4085   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4086     {
4087       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4088       gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4089     }
4090
4091   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4092     {
4093       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4094       gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4095     }
4096
4097   if (tree_view->priv->hadjustment != hadj)
4098     {
4099       tree_view->priv->hadjustment = hadj;
4100       gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4101       gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4102
4103       gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4104                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4105                           tree_view);
4106       need_adjust = TRUE;
4107     }
4108
4109   if (tree_view->priv->vadjustment != vadj)
4110     {
4111       tree_view->priv->vadjustment = vadj;
4112       gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4113       gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4114
4115       gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4116                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4117                           tree_view);
4118       need_adjust = TRUE;
4119     }
4120
4121   if (need_adjust)
4122     gtk_tree_view_adjustment_changed (NULL, tree_view);
4123 }
4124
4125
4126 /* Column and header operations */
4127
4128 /**
4129  * gtk_tree_view_get_headers_visible:
4130  * @tree_view: A #GtkTreeView.
4131  *
4132  * Returns TRUE if the headers on the @tree_view are visible.
4133  *
4134  * Return value: Whether the headers are visible or not.
4135  **/
4136 gboolean
4137 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
4138 {
4139   g_return_val_if_fail (tree_view != NULL, FALSE);
4140   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
4141
4142   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
4143 }
4144
4145 /**
4146  * gtk_tree_view_set_headers_visible:
4147  * @tree_view: A #GtkTreeView.
4148  * @headers_visible: TRUE if the headers are visible
4149  *
4150  * Sets the the visibility state of the headers.
4151  **/
4152 void
4153 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
4154                                    gboolean     headers_visible)
4155 {
4156   gint x, y;
4157   GList *list;
4158   GtkTreeViewColumn *column;
4159
4160   g_return_if_fail (tree_view != NULL);
4161   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4162
4163   headers_visible = !! headers_visible;
4164
4165   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
4166     return;
4167
4168   if (headers_visible)
4169     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
4170   else
4171     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
4172
4173   if (GTK_WIDGET_REALIZED (tree_view))
4174     {
4175       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
4176       if (headers_visible)
4177         {
4178           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
4179
4180           if (GTK_WIDGET_MAPPED (tree_view))
4181             gtk_tree_view_map_buttons (tree_view);
4182         }
4183       else
4184         {
4185           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
4186
4187           for (list = tree_view->priv->columns; list; list = list->next)
4188             {
4189               column = list->data;
4190               gtk_widget_unmap (column->button);
4191             }
4192           gdk_window_hide (tree_view->priv->header_window);
4193         }
4194     }
4195
4196   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
4197   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
4198   tree_view->priv->vadjustment->lower = 0;
4199   tree_view->priv->vadjustment->upper = tree_view->priv->height;
4200   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
4201
4202   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4203
4204   g_object_notify (G_OBJECT (tree_view), "headers_visible");
4205 }
4206
4207
4208 /**
4209  * gtk_tree_view_columns_autosize:
4210  * @tree_view: A #GtkTreeView.
4211  *
4212  * Resizes all columns to their optimal width.
4213  **/
4214 void
4215 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
4216 {
4217   gboolean dirty = FALSE;
4218   GList *list;
4219   GtkTreeViewColumn *column;
4220
4221   g_return_if_fail (tree_view != NULL);
4222   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4223
4224   for (list = tree_view->priv->columns; list; list = list->next)
4225     {
4226       column = list->data;
4227       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4228         continue;
4229       column->dirty = TRUE;
4230       dirty = TRUE;
4231     }
4232
4233   if (dirty)
4234     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4235 }
4236
4237 /**
4238  * gtk_tree_view_set_headers_clickable:
4239  * @tree_view: A #GtkTreeView.
4240  * @setting: TRUE if the columns are clickable.
4241  *
4242  * Allow the column title buttons to be clicked.
4243  **/
4244 void
4245 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
4246                                      gboolean   setting)
4247 {
4248   GList *list;
4249
4250   g_return_if_fail (tree_view != NULL);
4251   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4252   g_return_if_fail (tree_view->priv->model != NULL);
4253
4254   for (list = tree_view->priv->columns; list; list = list->next)
4255     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
4256
4257   g_object_notify (G_OBJECT (tree_view), "headers_clickable");
4258 }
4259
4260 /**
4261  * gtk_tree_view_append_column:
4262  * @tree_view: A #GtkTreeView.
4263  * @column: The #GtkTreeViewColumn to add.
4264  *
4265  * Appends @column to the list of columns.
4266  *
4267  * Return value: The number of columns in @tree_view after appending.
4268  **/
4269 gint
4270 gtk_tree_view_append_column (GtkTreeView       *tree_view,
4271                              GtkTreeViewColumn *column)
4272 {
4273   g_return_val_if_fail (tree_view != NULL, -1);
4274   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4275   g_return_val_if_fail (column != NULL, -1);
4276   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
4277   g_return_val_if_fail (column->tree_view == NULL, -1);
4278
4279   return gtk_tree_view_insert_column (tree_view, column, -1);
4280 }
4281
4282
4283 /**
4284  * gtk_tree_view_remove_column:
4285  * @tree_view: A #GtkTreeView.
4286  * @column: The #GtkTreeViewColumn to remove.
4287  *
4288  * Removes @column from @tree_view.
4289  *
4290  * Return value: The number of columns in @tree_view after removing.
4291  **/
4292 gint
4293 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
4294                              GtkTreeViewColumn *column)
4295 {
4296   g_return_val_if_fail (tree_view != NULL, -1);
4297   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4298   g_return_val_if_fail (column != NULL, -1);
4299   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
4300   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
4301
4302   _gtk_tree_view_column_unset_tree_view (column);
4303
4304   if (tree_view->priv->focus_column &&
4305       GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data) == column)
4306     tree_view->priv->focus_column = NULL;
4307
4308   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
4309
4310   g_object_unref (G_OBJECT (column));
4311
4312   tree_view->priv->n_columns--;
4313
4314   if (GTK_WIDGET_REALIZED (tree_view))
4315     {
4316       GList *list;
4317
4318       for (list = tree_view->priv->columns; list; list = list->next)
4319         {
4320           column = GTK_TREE_VIEW_COLUMN (list->data);
4321           if (column->visible)
4322             column->dirty = TRUE;
4323         }
4324
4325       if (tree_view->priv->n_columns == 0 &&
4326           gtk_tree_view_get_headers_visible (tree_view))
4327         gdk_window_hide (tree_view->priv->header_window);
4328
4329       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4330     }
4331
4332
4333   return tree_view->priv->n_columns;
4334 }
4335
4336 /**
4337  * gtk_tree_view_insert_column:
4338  * @tree_view: A #GtkTreeView.
4339  * @column: The #GtkTreeViewColumn to be inserted.
4340  * @position: The position to insert @column in.
4341  *
4342  * This inserts the @column into the @tree_view at @position.  If @position is
4343  * -1, then the column is inserted at the end.
4344  *
4345  * Return value: The number of columns in @tree_view after insertion.
4346  **/
4347 gint
4348 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
4349                              GtkTreeViewColumn *column,
4350                              gint               position)
4351 {
4352   g_return_val_if_fail (tree_view != NULL, -1);
4353   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4354   g_return_val_if_fail (column != NULL, -1);
4355   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
4356   g_return_val_if_fail (column->tree_view == NULL, -1);
4357
4358   g_object_ref (G_OBJECT (column));
4359
4360   if (tree_view->priv->n_columns == 0 &&
4361       GTK_WIDGET_REALIZED (tree_view) &&
4362       gtk_tree_view_get_headers_visible (tree_view))
4363     {
4364       gdk_window_show (tree_view->priv->header_window);
4365     }
4366
4367   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
4368                                             column, position);
4369   _gtk_tree_view_column_set_tree_view (column, tree_view);
4370   _gtk_tree_view_column_create_button (column);
4371
4372   tree_view->priv->n_columns++;
4373
4374
4375   if (GTK_WIDGET_REALIZED (tree_view))
4376     {
4377       GList *list;
4378
4379       for (list = tree_view->priv->columns; list; list = list->next)
4380         {
4381           column = GTK_TREE_VIEW_COLUMN (list->data);
4382           if (column->visible)
4383             column->dirty = TRUE;
4384         }
4385       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4386     }
4387
4388   return tree_view->priv->n_columns;
4389 }
4390
4391 /**
4392  * gtk_tree_view_insert_column_with_attributes:
4393  * @tree_view: A #GtkTreeView
4394  * @position: The position to insert the new column in.
4395  * @title: The title to set the header to.
4396  * @cell: The #GtkCellRenderer.
4397  * @Varargs: A NULL terminated list of attributes.
4398  *
4399  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
4400  * @position.  If @position is -1, then the newly created column is inserted at
4401  * the end.  The column is initialized with the attributes given.
4402  *
4403  * Return value: The number of columns in @tree_view after insertion.
4404  **/
4405 gint
4406 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
4407                                              gint             position,
4408                                              gchar           *title,
4409                                              GtkCellRenderer *cell,
4410                                              ...)
4411 {
4412   GtkTreeViewColumn *column;
4413   gchar *attribute;
4414   va_list args;
4415   gint column_id;
4416
4417   g_return_val_if_fail (tree_view != NULL, -1);
4418   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4419
4420   column = gtk_tree_view_column_new ();
4421
4422   gtk_tree_view_column_set_title (column, title);
4423   gtk_tree_view_column_set_cell_renderer (column, cell);
4424
4425   va_start (args, cell);
4426
4427   attribute = va_arg (args, gchar *);
4428
4429   while (attribute != NULL)
4430     {
4431       column_id = va_arg (args, gint);
4432       gtk_tree_view_column_add_attribute (column, attribute, column_id);
4433       attribute = va_arg (args, gchar *);
4434     }
4435
4436   va_end (args);
4437
4438   gtk_tree_view_insert_column (tree_view, column, position);
4439   g_object_unref (column);
4440
4441   return tree_view->priv->n_columns;
4442 }
4443
4444 /**
4445  * gtk_tree_view_get_column:
4446  * @tree_view: A #GtkTreeView.
4447  * @n: The position of the column, counting from 0.
4448  *
4449  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
4450  *
4451  * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
4452  * range of columns.
4453  **/
4454 GtkTreeViewColumn *
4455 gtk_tree_view_get_column (GtkTreeView *tree_view,
4456                           gint         n)
4457 {
4458   g_return_val_if_fail (tree_view != NULL, NULL);
4459   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
4460   g_return_val_if_fail (tree_view->priv->model != NULL, NULL);
4461
4462   if (n < 0 || n >= tree_view->priv->n_columns)
4463     return NULL;
4464
4465   if (tree_view->priv->columns == NULL)
4466     return NULL;
4467
4468   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
4469 }
4470
4471 void
4472 gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
4473                                    gint         col)
4474 {
4475   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4476
4477   if (tree_view->priv->expander_column != col)
4478     {
4479       tree_view->priv->expander_column = col;
4480
4481       g_object_notify (G_OBJECT (tree_view), "expander_column");
4482     }
4483 }
4484
4485 gint
4486 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
4487 {
4488   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4489
4490   return tree_view->priv->expander_column;
4491 }
4492
4493 /**
4494  * gtk_tree_view_scroll_to_point:
4495  * @tree_view: a #GtkTreeView
4496  * @tree_x: X coordinate of new top-left pixel of visible area
4497  * @tree_y: Y coordinate of new top-left pixel of visible area
4498  *
4499  * Scrolls the tree view such that the top-left corner of the visible
4500  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
4501  * in tree window coordinates.  The @tree_view must be realized before
4502  * this function is called.  If it isn't, you probably want ot be
4503  * using gtk_tree_view_scroll_to_cell.
4504  **/
4505 void
4506 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
4507                                gint         tree_x,
4508                                gint         tree_y)
4509 {
4510   GtkAdjustment *hadj;
4511   GtkAdjustment *vadj;
4512
4513   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4514   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
4515
4516   hadj = tree_view->priv->hadjustment;
4517   vadj = tree_view->priv->vadjustment;
4518
4519   gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
4520   gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
4521 }
4522
4523 /**
4524  * gtk_tree_view_scroll_to_cell
4525  * @tree_view: A #GtkTreeView.
4526  * @path: The path of the row to move to.
4527  * @column: The #GtkTreeViewColumn to move horizontally to.
4528  * @row_align: The vertical alignment of the row specified by @path.
4529  * @col_align: The horizontal alignment of the column specified by @column.
4530  *
4531  * Moves the alignments of @tree_view to the position specified by
4532  * @column and @path.  If @column is NULL, then no horizontal
4533  * scrolling occurs.  Likewise, if @path is NULL no vertical scrolling
4534  * occurs.  @row_align determines where the row is placed, and
4535  * @col_align determines where @column is placed.  Both are expected
4536  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
4537  * right/bottom alignment, 0.5 means center.
4538  **/
4539 void
4540 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
4541                               GtkTreePath       *path,
4542                               GtkTreeViewColumn *column,
4543                               gfloat             row_align,
4544                               gfloat             col_align)
4545 {
4546   GdkRectangle cell_rect;
4547   GdkRectangle vis_rect;
4548   gint dest_x, dest_y;
4549
4550   /* FIXME work on unmapped/unrealized trees? maybe implement when
4551    * we do incremental reflow for trees
4552    */
4553
4554   g_return_if_fail (tree_view != NULL);
4555   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4556   g_return_if_fail (row_align >= 0.0);
4557   g_return_if_fail (row_align <= 1.0);
4558   g_return_if_fail (col_align >= 0.0);
4559   g_return_if_fail (col_align <= 1.0);
4560   g_return_if_fail (path != NULL || column != NULL);
4561
4562   row_align = CLAMP (row_align, 0.0, 1.0);
4563   col_align = CLAMP (col_align, 0.0, 1.0);
4564
4565   if (! GTK_WIDGET_REALIZED (tree_view))
4566     {
4567       if (path)
4568         tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
4569       if (column)
4570         tree_view->priv->scroll_to_column = column;
4571       tree_view->priv->scroll_to_row_align = row_align;
4572       tree_view->priv->scroll_to_col_align = col_align;
4573
4574       return;
4575     }
4576
4577   gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
4578   gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
4579
4580   dest_x = vis_rect.x;
4581   dest_y = vis_rect.y;
4582
4583   if (path)
4584     {
4585       dest_x = cell_rect.x +
4586         cell_rect.width * row_align -
4587         vis_rect.width * row_align;
4588     }
4589
4590   if (column)
4591     {
4592       dest_y = cell_rect.y +
4593         cell_rect.height * col_align -
4594         vis_rect.height * col_align;
4595     }
4596
4597   gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
4598 }
4599
4600 /**
4601  * gtk_tree_view_get_path_at_pos:
4602  * @tree_view: A #GtkTreeView.
4603  * @window: The #GdkWindow to check against.
4604  * @x: The x position to be identified.
4605  * @y: The y position to be identified.
4606  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
4607  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
4608  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
4609  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
4610  *
4611  * Finds the path at the point (@x, @y) relative to @window.  If
4612  * @window is NULL, then the point is found relative to the widget
4613  * coordinates.  This function is expected to be called after an
4614  * event, with event->window being passed in as @window.  It is
4615  * primarily for things like popup menus.  If @path is non-NULL, then
4616  * it will be filled with the #GtkTreePath at that point.  This path
4617  * should be freed with #gtk_tree_path_free.  If @column is non-NULL,
4618  * then it will be filled with the column at that point. @cell_x and
4619  * @cell_y return the coordinates relative to the cell background
4620  * (i.e. the background_area passed to gtk_cell_renderer_render()).
4621  *
4622  * Return value: TRUE if a row exists at that coordinate.
4623  **/
4624 gboolean
4625 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
4626                                GdkWindow          *window,
4627                                gint                x,
4628                                gint                y,
4629                                GtkTreePath       **path,
4630                                GtkTreeViewColumn **column,
4631                                gint               *cell_x,
4632                                gint               *cell_y)
4633 {
4634   GtkRBTree *tree;
4635   GtkRBNode *node;
4636   gint y_offset;
4637
4638   g_return_val_if_fail (tree_view != NULL, FALSE);
4639   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
4640   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
4641
4642   if (window)
4643     g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
4644
4645   if (path)
4646     *path = NULL;
4647   if (column)
4648     *column = NULL;
4649
4650   if (x > tree_view->priv->hadjustment->upper)
4651     return FALSE;
4652
4653   if (x < 0 || y < 0)
4654     return FALSE;
4655
4656   if (column || cell_x)
4657     {
4658       GtkTreeViewColumn *tmp_column;
4659       GtkTreeViewColumn *last_column = NULL;
4660       GList *list;
4661       gint remaining_x = x;
4662       gboolean found = FALSE;
4663
4664       for (list = tree_view->priv->columns; list; list = list->next)
4665         {
4666           tmp_column = list->data;
4667
4668           if (tmp_column->visible == FALSE)
4669             continue;
4670
4671           last_column = tmp_column;
4672           if (remaining_x <= tmp_column->width)
4673             {
4674               found = TRUE;
4675
4676               if (column)
4677                 *column = tmp_column;
4678
4679               if (cell_x)
4680                 *cell_x = remaining_x;
4681
4682               break;
4683             }
4684           remaining_x -= tmp_column->width;
4685         }
4686
4687       if (!found)
4688         {
4689           if (column)
4690             *column = last_column;
4691
4692           if (cell_x)
4693             *cell_x = last_column->width + remaining_x;
4694         }
4695     }
4696
4697   if (window)
4698     {
4699       y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
4700                                           TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
4701                                           &tree, &node);
4702     }
4703   else
4704     {
4705       if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
4706         return FALSE;
4707
4708       y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
4709                                           TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
4710                                           &tree, &node);
4711     }
4712
4713   if (tree == NULL)
4714     return FALSE;
4715
4716   if (cell_y)
4717     *cell_y = y_offset;
4718
4719   if (path)
4720     *path = _gtk_tree_view_find_path (tree_view, tree, node);
4721
4722   return TRUE;
4723 }
4724
4725
4726 static void
4727 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
4728                                      GtkRBTree         *tree,
4729                                      GtkTreeViewColumn *column,
4730                                      gint              *x1,
4731                                      gint              *x2)
4732 {
4733   GtkTreeViewColumn *tmp_column = NULL;
4734   gint total_width;
4735   GList *list;
4736
4737   if (x1)
4738     *x1 = 0;
4739
4740   if (x2)
4741     *x2 = 0;
4742
4743   total_width = 0;
4744   for (list = tree_view->priv->columns; list; list = list->next)
4745     {
4746       tmp_column = list->data;
4747
4748       if (tmp_column == column)
4749         break;
4750
4751       if (tmp_column->visible)
4752         total_width += tmp_column->width;
4753     }
4754
4755   if (tmp_column != column)
4756     {
4757       g_warning (G_STRLOC": passed-in column isn't in the tree");
4758       return;
4759     }
4760
4761   if (x1)
4762     *x1 = total_width;
4763
4764   if (x2)
4765     {
4766       if (column->visible)
4767         *x2 = total_width + column->width;
4768       else
4769         *x2 = total_width; /* width of 0 */
4770     }
4771 }
4772
4773 static void
4774 gtk_tree_view_get_cell_xrange (GtkTreeView       *tree_view,
4775                                GtkRBTree         *tree,
4776                                GtkTreeViewColumn *column,
4777                                gint              *x1,
4778                                gint              *x2)
4779 {
4780   GtkTreeViewColumn *tmp_column = NULL;
4781   gint total_width;
4782   GList *list;
4783   gint i;
4784
4785   if (x1)
4786     *x1 = 0;
4787
4788   if (x2)
4789     *x2 = 0;
4790
4791   i = 0;
4792   total_width = 0;
4793   for (list = tree_view->priv->columns; list; list = list->next)
4794     {
4795       tmp_column = list->data;
4796
4797       if (tmp_column == column)
4798         break;
4799
4800       if (tmp_column->visible)
4801         total_width += tmp_column->width;
4802
4803       ++i;
4804     }
4805
4806   if (tmp_column != column)
4807     {
4808       g_warning (G_STRLOC": passed-in column isn't in the tree");
4809       return;
4810     }
4811
4812   /* Remember we're getting the cell range, i.e. the cell_area passed
4813    * to the cell renderer.
4814    */
4815
4816   if (i == tree_view->priv->expander_column)
4817     total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
4818
4819   if (x1)
4820     *x1 = total_width;
4821
4822   if (x2)
4823     {
4824       if (column->visible)
4825         *x2 = total_width + column->displayed_width;
4826       else
4827         *x2 = total_width; /* width of 0 */
4828     }
4829 }
4830
4831 static void
4832 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
4833                                 gint        *x1,
4834                                 gint        *x2)
4835 {
4836   gint x_offset = 0;
4837   GList *list;
4838   GtkTreeViewColumn *tmp_column = NULL;
4839   gint total_width;
4840   gint i;
4841
4842   i = 0;
4843   total_width = 0;
4844   for (list = tree_view->priv->columns; list; list = list->next)
4845     {
4846       tmp_column = list->data;
4847
4848       if (i == tree_view->priv->expander_column)
4849         {
4850           x_offset = total_width;
4851           break;
4852         }
4853
4854       if (tmp_column->visible)
4855         total_width += tmp_column->width;
4856
4857       ++i;
4858     }
4859
4860   if (x1)
4861     *x1 = x_offset;
4862
4863   if (tmp_column && tmp_column->visible)
4864     {
4865       /* +1 because x2 isn't included in the range. */
4866       if (x2)
4867         *x2 = x_offset + tree_view->priv->tab_offset + 1;
4868     }
4869   else
4870     {
4871       /* return an empty range, the expander column is hidden */
4872       if (x2)
4873         *x2 = x_offset;
4874     }
4875 }
4876
4877
4878 /**
4879  * gtk_tree_view_get_cell_area:
4880  * @tree_view: a #GtkTreeView
4881  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
4882  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
4883  * @rect: rectangle to fill with cell rect
4884  *
4885  * Fills the bounding rectangle in tree window coordinates for the
4886  * cell at the row specified by @path and the column specified by
4887  * @column.  If @path is %NULL, the y and height fields of the
4888  * rectangle will be filled with 0. If @column is %NULL, the x and
4889  * width fields will be filled with 0.  The sum of all cell rects does
4890  * not cover the entire tree; there are extra pixels in between rows,
4891  * for example. The returned rectangle is equivalent to the @cell_area
4892  * passed to gtk_cell_renderer_render().
4893  *
4894  **/
4895 void
4896 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
4897                              GtkTreePath        *path,
4898                              GtkTreeViewColumn  *column,
4899                              GdkRectangle       *rect)
4900 {
4901   GtkRBTree *tree = NULL;
4902   GtkRBNode *node = NULL;
4903
4904   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4905   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
4906   g_return_if_fail (rect != NULL);
4907
4908   rect->x = 0;
4909   rect->y = 0;
4910   rect->width = 0;
4911   rect->height = 0;
4912
4913   if (path)
4914     {
4915       /* Get vertical coords */
4916
4917       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
4918
4919       if (tree == NULL)
4920         {
4921           g_warning (G_STRLOC": no row corresponding to path");
4922           return;
4923         }
4924
4925       /* Remember that the rbtree stores node height including the vertical
4926        * separator, see comment at top of file.
4927        */
4928       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node);
4929
4930       rect->height = CELL_HEIGHT (node);
4931     }
4932
4933   if (column)
4934     {
4935       gint x2 = 0;
4936
4937       gtk_tree_view_get_cell_xrange (tree_view, tree, column, &rect->x, &x2);
4938       rect->width = x2 - rect->x;
4939     }
4940 }
4941
4942
4943 /**
4944  * gtk_tree_view_get_background_area:
4945  * @tree_view: a #GtkTreeView
4946  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
4947  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
4948  * @rect: rectangle to fill with cell background rect
4949  *
4950  * Fills the bounding rectangle in tree window coordinates for the
4951  * cell at the row specified by @path and the column specified by
4952  * @column.  If @path is %NULL, the y and height fields of the
4953  * rectangle will be filled with 0. If @column is %NULL, the x and
4954  * width fields will be filled with 0.  The returned rectangle is
4955  * equivalent to the @background_area passed to
4956  * gtk_cell_renderer_render().  These background areas tile to cover
4957  * the entire tree window (except for the area used for header
4958  * buttons). Contrast with the cell_area, returned by
4959  * gtk_tree_view_get_cell_area(), which returns only the cell itself,
4960  * excluding surrounding borders and the tree expander area.
4961  *
4962  **/
4963 void
4964 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
4965                                    GtkTreePath        *path,
4966                                    GtkTreeViewColumn  *column,
4967                                    GdkRectangle       *rect)
4968 {
4969   GtkRBTree *tree = NULL;
4970   GtkRBNode *node = NULL;
4971
4972   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4973   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
4974   g_return_if_fail (rect != NULL);
4975
4976   rect->x = 0;
4977   rect->y = 0;
4978   rect->width = 0;
4979   rect->height = 0;
4980
4981   if (path)
4982     {
4983       /* Get vertical coords */
4984
4985       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
4986
4987       if (tree == NULL)
4988         {
4989           g_warning (G_STRLOC": no row corresponding to path");
4990           return;
4991         }
4992
4993       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4994
4995       rect->height = BACKGROUND_HEIGHT (node);
4996     }
4997
4998   if (column)
4999     {
5000       gint x2 = 0;
5001
5002       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
5003       rect->width = x2 - rect->x;
5004     }
5005 }
5006
5007 static void
5008 gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
5009                                  GtkRBNode  *node,
5010                                  gpointer  data)
5011 {
5012   GtkTreeView *tree_view = data;
5013
5014   if (node->children)
5015     _gtk_rbtree_traverse (node->children,
5016                           node->children->root,
5017                           G_PRE_ORDER,
5018                           gtk_tree_view_expand_all_helper,
5019                           data);
5020   else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
5021     {
5022       GtkTreePath *path;
5023       GtkTreeIter iter;
5024       GtkTreeIter child;
5025
5026       node->children = _gtk_rbtree_new ();
5027       node->children->parent_tree = tree;
5028       node->children->parent_node = node;
5029       path = _gtk_tree_view_find_path (tree_view, tree, node);
5030       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5031       gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
5032       gtk_tree_view_build_tree (tree_view,
5033                                 node->children,
5034                                 &child,
5035                                 gtk_tree_path_get_depth (path) + 1,
5036                                 TRUE,
5037                                 GTK_WIDGET_REALIZED (tree_view));
5038       gtk_tree_path_free (path);
5039     }
5040 }
5041
5042 /**
5043  * gtk_tree_view_expand_all:
5044  * @tree_view: A #GtkTreeView.
5045  *
5046  * Recursively expands all nodes in the @tree_view.
5047  **/
5048 void
5049 gtk_tree_view_expand_all (GtkTreeView *tree_view)
5050 {
5051   g_return_if_fail (tree_view != NULL);
5052   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5053   g_return_if_fail (tree_view->priv->tree != NULL);
5054
5055   _gtk_rbtree_traverse (tree_view->priv->tree,
5056                         tree_view->priv->tree->root,
5057                         G_PRE_ORDER,
5058                         gtk_tree_view_expand_all_helper,
5059                         tree_view);
5060
5061   _gtk_tree_view_update_size (tree_view);
5062 }
5063
5064 static void
5065 gtk_tree_view_collapse_all_helper (GtkRBTree  *tree,
5066                                    GtkRBNode  *node,
5067                                    gpointer    data)
5068 {
5069   if (node->children)
5070     {
5071       GtkTreePath *path;
5072       GtkTreeIter iter;
5073
5074       path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
5075                                        node->children,
5076                                        node->children->root);
5077       gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
5078                                &iter,
5079                                path);
5080       gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
5081                                     node->children,
5082                                     &iter,
5083                                     gtk_tree_path_get_depth (path));
5084
5085       /* Ensure we don't have a dangling pointer to a dead node */
5086       ensure_unprelighted (GTK_TREE_VIEW (data));
5087
5088       _gtk_rbtree_remove (node->children);
5089       gtk_tree_path_free (path);
5090     }
5091 }
5092
5093 /**
5094  * gtk_tree_view_collapse_all:
5095  * @tree_view: A #GtkTreeView.
5096  *
5097  * Recursively collapses all visible, expanded nodes in @tree_view.
5098  **/
5099 void
5100 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
5101 {
5102   g_return_if_fail (tree_view != NULL);
5103   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5104   g_return_if_fail (tree_view->priv->tree != NULL);
5105
5106   _gtk_rbtree_traverse (tree_view->priv->tree,
5107                         tree_view->priv->tree->root,
5108                         G_PRE_ORDER,
5109                         gtk_tree_view_collapse_all_helper,
5110                         tree_view);
5111
5112   if (GTK_WIDGET_MAPPED (tree_view))
5113     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5114 }
5115
5116 /* FIXME the bool return values for expand_row and collapse_row are
5117  * not analagous; they should be TRUE if the row had children and
5118  * was not already in the requested state.
5119  */
5120
5121 /**
5122  * gtk_tree_view_expand_row:
5123  * @tree_view: a #GtkTreeView
5124  * @path: path to a row
5125  * @open_all: whether to recursively expand, or just expand immediate children
5126  *
5127  * Opens the row so its children are visible
5128  *
5129  * Return value: %TRUE if the row existed and had children
5130  **/
5131 gboolean
5132 gtk_tree_view_expand_row (GtkTreeView *tree_view,
5133                           GtkTreePath *path,
5134                           gboolean     open_all)
5135 {
5136   GtkTreeIter iter;
5137   GtkTreeIter child;
5138   GtkRBTree *tree;
5139   GtkRBNode *node;
5140
5141   g_return_val_if_fail (tree_view != NULL, FALSE);
5142   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5143   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
5144   g_return_val_if_fail (path != NULL, FALSE);
5145
5146   if (_gtk_tree_view_find_node (tree_view,
5147                                 path,
5148                                 &tree,
5149                                 &node))
5150     return FALSE;
5151
5152   if (node->children)
5153     return TRUE;
5154
5155   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5156   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
5157     return FALSE;
5158
5159   node->children = _gtk_rbtree_new ();
5160   node->children->parent_tree = tree;
5161   node->children->parent_node = node;
5162
5163   gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
5164   gtk_tree_view_build_tree (tree_view,
5165                             node->children,
5166                             &child,
5167                             gtk_tree_path_get_depth (path) + 1,
5168                             open_all,
5169                             GTK_WIDGET_REALIZED (tree_view));
5170
5171   if (GTK_WIDGET_MAPPED (tree_view))
5172     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5173
5174   return TRUE;
5175 }
5176
5177 /**
5178  * gtk_tree_view_collapse_row:
5179  * @tree_view: a #GtkTreeView
5180  * @path: path to a row in the @tree_view
5181  *
5182  * Collapses a row (hides its child rows).
5183  *
5184  * Return value: %TRUE if the row was expanded
5185  **/
5186 gboolean
5187 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
5188                             GtkTreePath *path)
5189 {
5190   GtkRBTree *tree;
5191   GtkRBNode *node;
5192   GtkTreeIter iter;
5193
5194   g_return_val_if_fail (tree_view != NULL, FALSE);
5195   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5196   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
5197   g_return_val_if_fail (path != NULL, FALSE);
5198
5199   if (_gtk_tree_view_find_node (tree_view,
5200                                 path,
5201                                 &tree,
5202                                 &node))
5203     return FALSE;
5204
5205   if (node->children == NULL)
5206     return FALSE;
5207
5208   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5209   gtk_tree_view_discover_dirty (tree_view,
5210                                 node->children,
5211                                 &iter,
5212                                 gtk_tree_path_get_depth (path));
5213
5214   /* Ensure we don't have a dangling pointer to a dead node */
5215   ensure_unprelighted (tree_view);
5216
5217   g_assert (tree_view->priv->prelight_node == NULL);
5218
5219   _gtk_rbtree_remove (node->children);
5220
5221   if (GTK_WIDGET_MAPPED (tree_view))
5222     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5223
5224   return TRUE;
5225 }
5226
5227 /**
5228  * gtk_tree_view_get_visible_rect:
5229  * @tree_view: a #GtkTreeView
5230  * @visible_rect: rectangle to fill
5231  *
5232  * Fills @visible_rect with the currently-visible region of the
5233  * buffer, in tree coordinates. Convert to widget coordinates with
5234  * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
5235  * 0,0 for row 0 of the tree, and cover the entire scrollable area of
5236  * the tree.
5237  **/
5238 void
5239 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
5240                                 GdkRectangle *visible_rect)
5241 {
5242   GtkWidget *widget;
5243
5244   g_return_if_fail (tree_view != NULL);
5245   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5246
5247   widget = GTK_WIDGET (tree_view);
5248
5249   if (visible_rect)
5250     {
5251       visible_rect->x = tree_view->priv->hadjustment->value;
5252       visible_rect->y = tree_view->priv->vadjustment->value;
5253       visible_rect->width = widget->allocation.width;
5254       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5255     }
5256 }
5257
5258 /**
5259  * gtk_tree_view_widget_to_tree_coords:
5260  * @tree_view: a #GtkTreeView
5261  * @wx: widget X coordinate
5262  * @wy: widget Y coordinate
5263  * @tx: return location for tree X coordinate
5264  * @ty: return location for tree Y coordinate
5265  *
5266  * Converts widget coordinates to coordinates for the
5267  * tree window (the full scrollable area of the tree).
5268  *
5269  **/
5270 void
5271 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
5272                                      gint         wx,
5273                                      gint         wy,
5274                                      gint        *tx,
5275                                      gint        *ty)
5276 {
5277   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5278
5279   if (tx)
5280     {
5281       *tx = wx + tree_view->priv->hadjustment->value;
5282     }
5283
5284   if (ty)
5285     {
5286       *ty = wy + tree_view->priv->vadjustment->value;
5287     }
5288 }
5289
5290 /**
5291  * gtk_tree_view_tree_to_widget_coords:
5292  * @tree_view: a #GtkTreeView
5293  * @tx: tree X coordinate
5294  * @ty: tree Y coordinate
5295  * @wx: return location for widget X coordinate
5296  * @wy: return location for widget Y coordinate
5297  *
5298  * Converts tree coordinates (coordinates in full scrollable
5299  * area of the tree) to widget coordinates.
5300  *
5301  **/
5302 void
5303 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
5304                                      gint         tx,
5305                                      gint         ty,
5306                                      gint        *wx,
5307                                      gint        *wy)
5308 {
5309   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5310
5311   if (wx)
5312     {
5313       *wx = tx - tree_view->priv->hadjustment->value;
5314     }
5315
5316   if (wy)
5317     {
5318       *wy = ty - tree_view->priv->vadjustment->value;
5319     }
5320 }
5321
5322 /**
5323  * gtk_tree_view_set_rules_hint
5324  * @tree_view: a #GtkTreeView
5325  * @setting: %TRUE if the tree requires reading across rows
5326  *
5327  * This function tells GTK+ that the user interface for your
5328  * application requires users to read across tree rows and associate
5329  * cells with one another. By default, GTK+ will then render the tree
5330  * with alternating row colors. <emphasis>DO NOT</emphasis> use it
5331  * just because you prefer the appearance of the ruled tree; that's a
5332  * question for the theme. Some themes will draw tree rows in
5333  * alternating colors even when rules are turned off, and users who
5334  * prefer that appearance all the time can choose those themes. You
5335  * should call this function only as a <emphasis>semantic</emphasis>
5336  * hint to the theme engine that your tree makes alternating colors
5337  * useful from a functional standpoint (since it has lots of columns,
5338  * generally).
5339  *
5340  **/
5341 void
5342 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
5343                               gboolean      setting)
5344 {
5345   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5346
5347   setting = setting != FALSE;
5348
5349   if (tree_view->priv->has_rules != setting)
5350     {
5351       tree_view->priv->has_rules = setting;
5352       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5353     }
5354
5355   g_object_notify (G_OBJECT (tree_view), "rules_hint");
5356 }
5357
5358 /**
5359  * gtk_tree_view_get_rules_hint
5360  * @tree_view: a #GtkTreeView
5361  *
5362  * Gets the setting set by gtk_tree_view_set_rules_hint().
5363  *
5364  * Return value: %TRUE if rules are useful for the user of this tree
5365  **/
5366 gboolean
5367 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
5368 {
5369   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5370
5371   return tree_view->priv->has_rules;
5372 }
5373
5374 /* Drag-and-drop */
5375
5376 static void
5377 set_source_row (GdkDragContext *context,
5378                 GtkTreeModel   *model,
5379                 GtkTreePath    *source_row)
5380 {
5381   g_object_set_data_full (G_OBJECT (context),
5382                           "gtk-tree-view-source-row",
5383                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
5384                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
5385 }
5386
5387 static GtkTreePath*
5388 get_source_row (GdkDragContext *context)
5389 {
5390   GtkTreeRowReference *ref =
5391     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
5392
5393   if (ref)
5394     return gtk_tree_row_reference_get_path (ref);
5395   else
5396     return NULL;
5397 }
5398
5399
5400 static void
5401 set_dest_row (GdkDragContext *context,
5402               GtkTreeModel   *model,
5403               GtkTreePath    *dest_row)
5404 {
5405   g_object_set_data_full (G_OBJECT (context),
5406                           "gtk-tree-view-dest-row",
5407                           dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
5408                           (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
5409 }
5410
5411 static GtkTreePath*
5412 get_dest_row (GdkDragContext *context)
5413 {
5414   GtkTreeRowReference *ref =
5415     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
5416
5417   if (ref)
5418     return gtk_tree_row_reference_get_path (ref);
5419   else
5420     return NULL;
5421 }
5422
5423 /* Get/set whether drag_motion requested the drag data and
5424  * drag_data_received should thus not actually insert the data,
5425  * since the data doesn't result from a drop.
5426  */
5427 static void
5428 set_status_pending (GdkDragContext *context,
5429                     GdkDragAction   suggested_action)
5430 {
5431   g_object_set_data (G_OBJECT (context),
5432                      "gtk-tree-view-status-pending",
5433                      GINT_TO_POINTER (suggested_action));
5434 }
5435
5436 static GdkDragAction
5437 get_status_pending (GdkDragContext *context)
5438 {
5439   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5440                                              "gtk-tree-view-status-pending"));
5441 }
5442
5443 typedef struct _TreeViewDragInfo TreeViewDragInfo;
5444
5445 struct _TreeViewDragInfo
5446 {
5447   GdkModifierType start_button_mask;
5448   GtkTargetList *source_target_list;
5449   GdkDragAction source_actions;
5450   GClosure *row_draggable_closure;
5451
5452   GtkTargetList *dest_target_list;
5453   GClosure *location_droppable_closure;
5454
5455   guint source_set : 1;
5456   guint dest_set : 1;
5457 };
5458
5459 static TreeViewDragInfo*
5460 get_info (GtkTreeView *tree_view)
5461 {
5462   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
5463 }
5464
5465 static void
5466 clear_source_info (TreeViewDragInfo *di)
5467 {
5468   if (di->source_target_list)
5469     gtk_target_list_unref (di->source_target_list);
5470
5471   if (di->row_draggable_closure)
5472     g_closure_unref (di->row_draggable_closure);
5473
5474   di->source_target_list = NULL;
5475   di->row_draggable_closure = NULL;
5476 }
5477
5478 static void
5479 clear_dest_info (TreeViewDragInfo *di)
5480 {
5481   if (di->location_droppable_closure)
5482     g_closure_unref (di->location_droppable_closure);
5483
5484   if (di->dest_target_list)
5485     gtk_target_list_unref (di->dest_target_list);
5486
5487   di->location_droppable_closure = NULL;
5488   di->dest_target_list = NULL;
5489 }
5490
5491 static void
5492 destroy_info (TreeViewDragInfo *di)
5493 {
5494   clear_source_info (di);
5495   clear_dest_info (di);
5496   g_free (di);
5497 }
5498
5499 static TreeViewDragInfo*
5500 ensure_info (GtkTreeView *tree_view)
5501 {
5502   TreeViewDragInfo *di;
5503
5504   di = get_info (tree_view);
5505
5506   if (di == NULL)
5507     {
5508       di = g_new0 (TreeViewDragInfo, 1);
5509
5510       g_object_set_data_full (G_OBJECT (tree_view),
5511                               "gtk-tree-view-drag-info",
5512                               di,
5513                               (GDestroyNotify) destroy_info);
5514     }
5515
5516   return di;
5517 }
5518
5519 static void
5520 remove_info (GtkTreeView *tree_view)
5521 {
5522   g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
5523 }
5524
5525 #define SCROLL_EDGE_SIZE 15
5526
5527 static gint
5528 drag_scan_timeout (gpointer data)
5529 {
5530   GtkTreeView *tree_view;
5531   gint x, y;
5532   GdkModifierType state;
5533   GtkTreePath *path = NULL;
5534   GtkTreeViewColumn *column = NULL;
5535   GdkRectangle visible_rect;
5536
5537   tree_view = GTK_TREE_VIEW (data);
5538
5539   gdk_window_get_pointer (tree_view->priv->bin_window,
5540                           &x, &y, &state);
5541
5542   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
5543
5544   /* See if we are near the edge. */
5545   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
5546       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
5547       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
5548       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
5549     {
5550       gtk_tree_view_get_path_at_pos (tree_view,
5551                                      tree_view->priv->bin_window,
5552                                      x, y,
5553                                      &path,
5554                                      &column,
5555                                      NULL,
5556                                      NULL);
5557
5558       if (path != NULL)
5559         {
5560           gtk_tree_view_scroll_to_cell (tree_view,
5561                                         path,
5562                                         column,
5563                                         0.5, 0.5);
5564
5565           gtk_tree_path_free (path);
5566         }
5567     }
5568
5569   return TRUE;
5570 }
5571
5572
5573 static void
5574 ensure_scroll_timeout (GtkTreeView *tree_view)
5575 {
5576   if (tree_view->priv->scroll_timeout == 0)
5577     tree_view->priv->scroll_timeout = gtk_timeout_add (50, drag_scan_timeout, tree_view);
5578 }
5579
5580 static void
5581 remove_scroll_timeout (GtkTreeView *tree_view)
5582 {
5583   if (tree_view->priv->scroll_timeout != 0)
5584     {
5585       gtk_timeout_remove (tree_view->priv->scroll_timeout);
5586       tree_view->priv->scroll_timeout = 0;
5587     }
5588 }
5589
5590 void
5591 gtk_tree_view_set_rows_drag_source (GtkTreeView              *tree_view,
5592                                     GdkModifierType           start_button_mask,
5593                                     const GtkTargetEntry     *targets,
5594                                     gint                      n_targets,
5595                                     GdkDragAction             actions,
5596                                     GtkTreeViewDraggableFunc  row_draggable_func,
5597                                     gpointer                  user_data)
5598 {
5599   TreeViewDragInfo *di;
5600
5601   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5602
5603   di = ensure_info (tree_view);
5604   clear_source_info (di);
5605
5606   di->start_button_mask = start_button_mask;
5607   di->source_target_list = gtk_target_list_new (targets, n_targets);
5608   di->source_actions = actions;
5609
5610   if (row_draggable_func)
5611     {
5612       di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
5613                                                   user_data, NULL);
5614       g_closure_ref (di->row_draggable_closure);
5615       g_closure_sink (di->row_draggable_closure);
5616     }
5617
5618   di->source_set = TRUE;
5619 }
5620
5621 void
5622 gtk_tree_view_set_rows_drag_dest (GtkTreeView              *tree_view,
5623                                   const GtkTargetEntry     *targets,
5624                                   gint                      n_targets,
5625                                   GdkDragAction             actions,
5626                                   GtkTreeViewDroppableFunc  location_droppable_func,
5627                                   gpointer                  user_data)
5628 {
5629   TreeViewDragInfo *di;
5630
5631   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5632
5633   gtk_drag_dest_set (GTK_WIDGET (tree_view),
5634                      0,
5635                      NULL,
5636                      0,
5637                      actions);
5638
5639   di = ensure_info (tree_view);
5640   clear_dest_info (di);
5641
5642   if (targets)
5643     di->dest_target_list = gtk_target_list_new (targets, n_targets);
5644
5645   if (location_droppable_func)
5646     {
5647       di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
5648                                                        user_data, NULL);
5649       g_closure_ref (di->location_droppable_closure);
5650       g_closure_sink (di->location_droppable_closure);
5651     }
5652
5653   di->dest_set = TRUE;
5654 }
5655
5656 void
5657 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
5658 {
5659   TreeViewDragInfo *di;
5660
5661   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5662
5663   di = get_info (tree_view);
5664
5665   if (di)
5666     {
5667       if (di->source_set)
5668         {
5669           clear_source_info (di);
5670           di->source_set = FALSE;
5671         }
5672
5673       if (!di->dest_set && !di->source_set)
5674         remove_info (tree_view);
5675     }
5676 }
5677
5678 void
5679 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
5680 {
5681   TreeViewDragInfo *di;
5682
5683   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5684
5685   di = get_info (tree_view);
5686
5687   if (di)
5688     {
5689       if (di->dest_set)
5690         {
5691           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
5692           clear_dest_info (di);
5693           di->dest_set = FALSE;
5694         }
5695
5696       if (!di->dest_set && !di->source_set)
5697         remove_info (tree_view);
5698     }
5699 }
5700
5701 void
5702 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
5703                                  GtkTreePath            *path,
5704                                  GtkTreeViewDropPosition pos)
5705 {
5706   GtkTreePath *current_dest;
5707   /* Note; this function is exported to allow a custom DND
5708    * implementation, so it can't touch TreeViewDragInfo
5709    */
5710
5711   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5712
5713   current_dest = NULL;
5714
5715   if (tree_view->priv->drag_dest_row)
5716     current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
5717
5718   if (current_dest)
5719     {
5720       gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
5721       gtk_tree_path_free (current_dest);
5722     }
5723
5724   if (tree_view->priv->drag_dest_row)
5725     gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
5726
5727   tree_view->priv->drag_dest_pos = pos;
5728
5729   if (path)
5730     {
5731       tree_view->priv->drag_dest_row =
5732         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
5733       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
5734     }
5735   else
5736     tree_view->priv->drag_dest_row = NULL;
5737 }
5738
5739 void
5740 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
5741                                  GtkTreePath             **path,
5742                                  GtkTreeViewDropPosition  *pos)
5743 {
5744   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5745
5746   if (path)
5747     {
5748       if (tree_view->priv->drag_dest_row)
5749         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
5750       else
5751         *path = NULL;
5752     }
5753
5754   if (pos)
5755     *pos = tree_view->priv->drag_dest_pos;
5756 }
5757
5758 gboolean
5759 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
5760                                    gint                     drag_x,
5761                                    gint                     drag_y,
5762                                    GtkTreePath            **path,
5763                                    GtkTreeViewDropPosition *pos)
5764 {
5765   gint cell_y;
5766   gdouble offset_into_row;
5767   gdouble quarter;
5768   gint x, y;
5769   GdkRectangle cell;
5770   GtkTreeViewColumn *column = NULL;
5771   GtkTreePath *tmp_path = NULL;
5772
5773   /* Note; this function is exported to allow a custom DND
5774    * implementation, so it can't touch TreeViewDragInfo
5775    */
5776
5777   g_return_val_if_fail (tree_view != NULL, FALSE);
5778   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
5779   g_return_val_if_fail (drag_x >= 0, FALSE);
5780   g_return_val_if_fail (drag_y >= 0, FALSE);
5781   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
5782
5783   if (path)
5784     *path = NULL;
5785
5786   /* remember that drag_x and drag_y are in widget coords, convert to tree window */
5787
5788   gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
5789                                        &x, &y);
5790
5791   /* If in the top quarter of a row, we drop before that row; if
5792    * in the bottom quarter, drop after that row; if in the middle,
5793    * and the row has children, drop into the row.
5794    */
5795
5796   if (!gtk_tree_view_get_path_at_pos (tree_view,
5797                                       tree_view->priv->bin_window,
5798                                       x, y,
5799                                       &tmp_path,
5800                                       &column,
5801                                       NULL,
5802                                       &cell_y))
5803     return FALSE;
5804
5805   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
5806                                      &cell);
5807
5808   offset_into_row = cell_y;
5809
5810   if (path)
5811     *path = tmp_path;
5812   else
5813     gtk_tree_path_free (tmp_path);
5814
5815   tmp_path = NULL;
5816
5817   quarter = cell.height / 4.0;
5818
5819   if (pos)
5820     {
5821       if (offset_into_row < quarter)
5822         {
5823           *pos = GTK_TREE_VIEW_DROP_BEFORE;
5824         }
5825       else if (offset_into_row < quarter * 2)
5826         {
5827           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
5828         }
5829       else if (offset_into_row < quarter * 3)
5830         {
5831           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
5832         }
5833       else
5834         {
5835           *pos = GTK_TREE_VIEW_DROP_AFTER;
5836         }
5837     }
5838
5839   return TRUE;
5840 }
5841
5842 static gboolean
5843 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
5844                                         GdkEventMotion   *event)
5845 {
5846   GdkDragContext *context;
5847   TreeViewDragInfo *di;
5848   GtkTreePath *path = NULL;
5849   gint button;
5850   gint cell_x, cell_y;
5851   GtkTreeModel *model;
5852
5853   di = get_info (tree_view);
5854
5855   if (di == NULL)
5856     return FALSE;
5857
5858   if (tree_view->priv->pressed_button < 0)
5859     return FALSE;
5860
5861   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
5862                                  tree_view->priv->press_start_x,
5863                                  tree_view->priv->press_start_y,
5864                                  event->x, event->y))
5865     return FALSE;
5866
5867   model = gtk_tree_view_get_model (tree_view);
5868
5869   if (model == NULL)
5870     return FALSE;
5871
5872   button = tree_view->priv->pressed_button;
5873   tree_view->priv->pressed_button = -1;
5874
5875   gtk_tree_view_get_path_at_pos (tree_view,
5876                                  tree_view->priv->bin_window,
5877                                  tree_view->priv->press_start_x,
5878                                  tree_view->priv->press_start_y,
5879                                  &path,
5880                                  NULL,
5881                                  &cell_x,
5882                                  &cell_y);
5883
5884   if (path == NULL)
5885     return FALSE;
5886
5887   /* FIXME if the path doesn't match the row_draggable predicate,
5888    * return FALSE and free path
5889    */
5890
5891   /* FIXME Check whether we're a start button, if not return FALSE and
5892    * free path
5893    */
5894
5895   context = gtk_drag_begin (GTK_WIDGET (tree_view),
5896                             di->source_target_list,
5897                             di->source_actions,
5898                             button,
5899                             (GdkEvent*)event);
5900
5901   gtk_drag_set_icon_default (context);
5902
5903   {
5904     GdkPixmap *row_pix;
5905
5906     row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
5907                                                   path);
5908
5909     gtk_drag_set_icon_pixmap (context,
5910                               gdk_drawable_get_colormap (row_pix),
5911                               row_pix,
5912                               NULL,
5913                               /* the + 1 is for the black border in the icon */
5914                               tree_view->priv->press_start_x + 1,
5915                               cell_y + 1);
5916
5917     gdk_pixmap_unref (row_pix);
5918   }
5919
5920   set_source_row (context, model, path);
5921   gtk_tree_path_free (path);
5922
5923   return TRUE;
5924 }
5925
5926 /* Default signal implementations for the drag signals */
5927
5928 static void
5929 gtk_tree_view_drag_begin (GtkWidget      *widget,
5930                           GdkDragContext *context)
5931 {
5932   /* do nothing */
5933 }
5934
5935 static void
5936 gtk_tree_view_drag_end (GtkWidget      *widget,
5937                         GdkDragContext *context)
5938 {
5939   /* do nothing */
5940 }
5941
5942 static void
5943 gtk_tree_view_drag_data_get (GtkWidget        *widget,
5944                              GdkDragContext   *context,
5945                              GtkSelectionData *selection_data,
5946                              guint             info,
5947                              guint             time)
5948 {
5949   GtkTreeView *tree_view;
5950   GtkTreeModel *model;
5951   TreeViewDragInfo *di;
5952   GtkTreePath *source_row;
5953
5954   tree_view = GTK_TREE_VIEW (widget);
5955
5956   model = gtk_tree_view_get_model (tree_view);
5957
5958   if (model == NULL)
5959     return;
5960
5961   di = get_info (GTK_TREE_VIEW (widget));
5962
5963   if (di == NULL)
5964     return;
5965
5966   source_row = get_source_row (context);
5967
5968   if (source_row == NULL)
5969     return;
5970
5971   /* We can implement the GTK_TREE_MODEL_ROW target generically for
5972    * any model; for DragSource models there are some other targets
5973    * we also support.
5974    */
5975
5976   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
5977       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
5978                                           source_row,
5979                                           selection_data))
5980     goto done;
5981
5982   /* If drag_data_get does nothing, try providing row data. */
5983   if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
5984     {
5985       gtk_selection_data_set_tree_row (selection_data,
5986                                        model,
5987                                        source_row);
5988     }
5989
5990  done:
5991   gtk_tree_path_free (source_row);
5992 }
5993
5994
5995 static gboolean
5996 check_model_dnd (GtkTreeModel *model,
5997                  GType         required_iface,
5998                  const gchar  *signal)
5999 {
6000   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6001     {
6002       g_warning ("You must override the default '%s' handler "
6003                  "on GtkTreeView when using models that don't support "
6004                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6005                  "is to connect to '%s' and call "
6006                  "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
6007                  "the default handler from running. Look at the source code "
6008                  "for the default handler in gtktreeview.c to get an idea what "
6009                  "your handler should do. (gtktreeview.c is in the GTK source "
6010                  "code.) If you're using GTK from a language other than C, "
6011                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6012                  signal, g_type_name (required_iface), signal);
6013       return FALSE;
6014     }
6015   else
6016     return TRUE;
6017 }
6018
6019 static void
6020 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
6021                                 GdkDragContext *context)
6022 {
6023   TreeViewDragInfo *di;
6024   GtkTreeModel *model;
6025   GtkTreeView *tree_view;
6026   GtkTreePath *source_row;
6027
6028   tree_view = GTK_TREE_VIEW (widget);
6029   model = gtk_tree_view_get_model (tree_view);
6030
6031   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
6032     return;
6033
6034   di = get_info (tree_view);
6035
6036   if (di == NULL)
6037     return;
6038
6039   source_row = get_source_row (context);
6040
6041   if (source_row == NULL)
6042     return;
6043
6044   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6045                                          source_row);
6046
6047   gtk_tree_path_free (source_row);
6048
6049   set_source_row (context, NULL, NULL);
6050 }
6051
6052 static void
6053 remove_open_timeout (GtkTreeView *tree_view)
6054 {
6055   if (tree_view->priv->open_dest_timeout != 0)
6056     {
6057       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
6058       tree_view->priv->open_dest_timeout = 0;
6059     }
6060 }
6061
6062 static void
6063 gtk_tree_view_drag_leave (GtkWidget      *widget,
6064                           GdkDragContext *context,
6065                           guint             time)
6066 {
6067   TreeViewDragInfo *di;
6068
6069   di = get_info (GTK_TREE_VIEW (widget));
6070
6071   /* unset any highlight row */
6072   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6073                                    NULL,
6074                                    GTK_TREE_VIEW_DROP_BEFORE);
6075
6076   remove_scroll_timeout (GTK_TREE_VIEW (widget));
6077   remove_open_timeout (GTK_TREE_VIEW (widget));
6078 }
6079
6080 static gint
6081 open_row_timeout (gpointer data)
6082 {
6083   GtkTreeView *tree_view = data;
6084   GtkTreePath *dest_path = NULL;
6085   GtkTreeViewDropPosition pos;
6086
6087   gtk_tree_view_get_drag_dest_row (tree_view,
6088                                    &dest_path,
6089                                    &pos);
6090
6091   if (dest_path &&
6092       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6093        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6094     {
6095       gtk_tree_view_expand_row (tree_view,
6096                                 dest_path,
6097                                 FALSE);
6098       tree_view->priv->open_dest_timeout = 0;
6099
6100       gtk_tree_path_free (dest_path);
6101
6102       return FALSE;
6103     }
6104   else
6105     {
6106       if (dest_path)
6107         gtk_tree_path_free (dest_path);
6108       return TRUE;
6109     }
6110 }
6111
6112 /* Returns TRUE if event should not be propagated to parent widgets */
6113 static gboolean
6114 set_destination_row (GtkTreeView    *tree_view,
6115                      GdkDragContext *context,
6116                      gint            x,
6117                      gint            y,
6118                      GdkDragAction  *suggested_action,
6119                      GdkAtom        *target)
6120 {
6121   GtkTreePath *path = NULL;
6122   GtkTreeViewDropPosition pos;
6123   GtkTreeViewDropPosition old_pos;
6124   TreeViewDragInfo *di;
6125   GtkWidget *widget;
6126   GtkTreePath *old_dest_path = NULL;
6127
6128   *suggested_action = 0;
6129   *target = GDK_NONE;
6130
6131   widget = GTK_WIDGET (tree_view);
6132
6133   di = get_info (tree_view);
6134
6135   if (di == NULL)
6136     {
6137       /* someone unset us as a drag dest, note that if
6138        * we return FALSE drag_leave isn't called
6139        */
6140
6141       gtk_tree_view_set_drag_dest_row (tree_view,
6142                                        NULL,
6143                                        GTK_TREE_VIEW_DROP_BEFORE);
6144
6145       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6146       remove_open_timeout (GTK_TREE_VIEW (widget));
6147
6148       return FALSE; /* no longer a drop site */
6149     }
6150
6151   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
6152   if (*target == GDK_NONE)
6153     {
6154       return FALSE;
6155     }
6156
6157   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6158                                           x, y,
6159                                           &path,
6160                                           &pos))
6161     {
6162       /* can't drop here */
6163       remove_open_timeout (tree_view);
6164
6165       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6166                                        NULL,
6167                                        GTK_TREE_VIEW_DROP_BEFORE);
6168
6169       /* don't propagate to parent though */
6170       return TRUE;
6171     }
6172
6173   g_assert (path);
6174
6175   /* If we left the current row's "open" zone, unset the timeout for
6176    * opening the row
6177    */
6178   gtk_tree_view_get_drag_dest_row (tree_view,
6179                                    &old_dest_path,
6180                                    &old_pos);
6181
6182   if (old_dest_path &&
6183       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6184        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6185          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6186     remove_open_timeout (tree_view);
6187
6188   if (old_dest_path)
6189     gtk_tree_path_free (old_dest_path);
6190
6191   if (TRUE /* FIXME if the location droppable predicate */)
6192     {
6193       GtkWidget *source_widget;
6194
6195       *suggested_action = context->suggested_action;
6196
6197       source_widget = gtk_drag_get_source_widget (context);
6198
6199       if (source_widget == widget)
6200         {
6201           /* Default to MOVE, unless the user has
6202            * pressed ctrl or alt to affect available actions
6203            */
6204           if ((context->actions & GDK_ACTION_MOVE) != 0)
6205             *suggested_action = GDK_ACTION_MOVE;
6206         }
6207
6208       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6209                                        path, pos);
6210     }
6211   else
6212     {
6213       /* can't drop here */
6214       remove_open_timeout (tree_view);
6215
6216       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6217                                        NULL,
6218                                        GTK_TREE_VIEW_DROP_BEFORE);
6219     }
6220
6221   return TRUE;
6222 }
6223
6224 static gboolean
6225 gtk_tree_view_drag_motion (GtkWidget        *widget,
6226                            GdkDragContext   *context,
6227                            gint              x,
6228                            gint              y,
6229                            guint             time)
6230 {
6231   GtkTreePath *path = NULL;
6232   GtkTreeViewDropPosition pos;
6233   GtkTreeView *tree_view;
6234   GdkDragAction suggested_action = 0;
6235   GdkAtom target;
6236
6237   tree_view = GTK_TREE_VIEW (widget);
6238
6239   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
6240     return FALSE;
6241
6242   ensure_scroll_timeout (tree_view);
6243
6244   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6245
6246   if (path == NULL)
6247     {
6248       /* Can't drop here. */
6249       gdk_drag_status (context, 0, time);
6250     }
6251   else
6252     {
6253       if (tree_view->priv->open_dest_timeout == 0 &&
6254           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6255            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6256         {
6257           tree_view->priv->open_dest_timeout =
6258             gtk_timeout_add (500, open_row_timeout, tree_view);
6259         }
6260
6261       if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
6262         {
6263           /* Request data so we can use the source row when
6264            * determining whether to accept the drop
6265            */
6266           set_status_pending (context, suggested_action);
6267           gtk_drag_get_data (widget, context, target, time);
6268         }
6269       else
6270         {
6271           set_status_pending (context, 0);
6272           gdk_drag_status (context, suggested_action, time);
6273         }
6274     }
6275
6276   if (path)
6277     gtk_tree_path_free (path);
6278
6279   return TRUE;
6280 }
6281
6282 static GtkTreePath*
6283 get_logical_dest_row (GtkTreeView *tree_view)
6284
6285 {
6286   /* adjust path to point to the row the drop goes in front of */
6287   GtkTreePath *path = NULL;
6288   GtkTreeViewDropPosition pos;
6289
6290   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6291
6292   if (path == NULL)
6293     return NULL;
6294
6295   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6296     ; /* do nothing */
6297   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6298            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6299     {
6300       /* get first child, drop before it */
6301       gtk_tree_path_append_index (path, 0);
6302     }
6303   else
6304     {
6305       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6306       gtk_tree_path_next (path);
6307     }
6308
6309   return path;
6310 }
6311
6312 static gboolean
6313 gtk_tree_view_drag_drop (GtkWidget        *widget,
6314                          GdkDragContext   *context,
6315                          gint              x,
6316                          gint              y,
6317                          guint             time)
6318 {
6319   GtkTreeView *tree_view;
6320   GtkTreePath *path;
6321   GdkDragAction suggested_action = 0;
6322   GdkAtom target = GDK_NONE;
6323   TreeViewDragInfo *di;
6324   GtkTreeModel *model;
6325
6326   tree_view = GTK_TREE_VIEW (widget);
6327
6328   model = gtk_tree_view_get_model (tree_view);
6329
6330   remove_scroll_timeout (GTK_TREE_VIEW (widget));
6331   remove_open_timeout (GTK_TREE_VIEW (widget));
6332
6333   di = get_info (tree_view);
6334
6335   if (di == NULL)
6336     return FALSE;
6337
6338   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
6339     return FALSE;
6340
6341   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
6342     return FALSE;
6343
6344   path = get_logical_dest_row (tree_view);
6345
6346   if (target != GDK_NONE && path != NULL)
6347     {
6348       /* in case a motion had requested drag data, change things so we
6349        * treat drag data receives as a drop.
6350        */
6351       set_status_pending (context, 0);
6352
6353       set_dest_row (context, model, path);
6354     }
6355
6356   if (path)
6357     gtk_tree_path_free (path);
6358
6359   /* Unset this thing */
6360   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6361                                    NULL,
6362                                    GTK_TREE_VIEW_DROP_BEFORE);
6363
6364   if (target != GDK_NONE)
6365     {
6366       gtk_drag_get_data (widget, context, target, time);
6367       return TRUE;
6368     }
6369   else
6370     return FALSE;
6371 }
6372
6373 static void
6374 gtk_tree_view_drag_data_received (GtkWidget        *widget,
6375                                   GdkDragContext   *context,
6376                                   gint              x,
6377                                   gint              y,
6378                                   GtkSelectionData *selection_data,
6379                                   guint             info,
6380                                   guint             time)
6381 {
6382   GtkTreePath *path;
6383   TreeViewDragInfo *di;
6384   gboolean accepted = FALSE;
6385   GtkTreeModel *model;
6386   GtkTreeView *tree_view;
6387   GtkTreePath *dest_row;
6388   GdkDragAction suggested_action;
6389
6390   tree_view = GTK_TREE_VIEW (widget);
6391
6392   model = gtk_tree_view_get_model (tree_view);
6393
6394   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
6395     return;
6396
6397   di = get_info (tree_view);
6398
6399   if (di == NULL)
6400     return;
6401
6402   suggested_action = get_status_pending (context);
6403
6404   if (suggested_action)
6405     {
6406       /* We are getting this data due to a request in drag_motion,
6407        * rather than due to a request in drag_drop, so we are just
6408        * supposed to call drag_status, not actually paste in the
6409        * data.
6410        */
6411       path = get_logical_dest_row (tree_view);
6412
6413       if (path == NULL)
6414         suggested_action = 0;
6415
6416       if (suggested_action)
6417         {
6418           GtkTreeModel *src_model = NULL;
6419           GtkTreePath *src_path = NULL;
6420
6421           if (!gtk_selection_data_get_tree_row (selection_data,
6422                                                 &src_model,
6423                                                 &src_path))
6424             suggested_action = 0;
6425
6426           if (suggested_action)
6427             {
6428               if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6429                                                          src_model,
6430                                                          src_path,
6431                                                          path))
6432                 suggested_action = 0;
6433
6434               gtk_tree_path_free (src_path);
6435             }
6436         }
6437
6438       gdk_drag_status (context, suggested_action, time);
6439
6440       if (path)
6441         gtk_tree_path_free (path);
6442
6443       /* If you can't drop, remove user drop indicator until the next motion */
6444       if (suggested_action == 0)
6445         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6446                                          NULL,
6447                                          GTK_TREE_VIEW_DROP_BEFORE);
6448
6449       return;
6450     }
6451
6452   dest_row = get_dest_row (context);
6453
6454   if (dest_row == NULL)
6455     return;
6456
6457   if (selection_data->length >= 0)
6458     {
6459       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6460                                                  dest_row,
6461                                                  selection_data))
6462         accepted = TRUE;
6463     }
6464
6465   gtk_drag_finish (context,
6466                    accepted,
6467                    (context->action == GDK_ACTION_MOVE),
6468                    time);
6469
6470   gtk_tree_path_free (dest_row);
6471
6472   /* drop dest_row */
6473   set_dest_row (context, NULL, NULL);
6474 }