]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
78d093c56c7724af81a42fb4fdea36ef1c3266ed
[~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 "gtktreeprivate.h"
24 #include "gtkcellrenderer.h"
25 #include "gtksignal.h"
26 #include "gtkmain.h"
27 #include "gtkbutton.h"
28 #include "gtkalignment.h"
29 #include "gtklabel.h"
30
31 #include <gdk/gdkkeysyms.h>
32
33
34 /* the width of the column resize windows */
35 #define TREE_VIEW_DRAG_WIDTH 6
36 #define TREE_VIEW_EXPANDER_WIDTH 14
37 #define TREE_VIEW_EXPANDER_HEIGHT 14
38 #define TREE_VIEW_VERTICAL_SEPARATOR 2
39 #define TREE_VIEW_HORIZONTAL_SEPARATOR 0
40
41
42 typedef struct _GtkTreeViewChild GtkTreeViewChild;
43
44 struct _GtkTreeViewChild
45 {
46   GtkWidget *widget;
47   gint x;
48   gint y;
49 };
50
51
52 static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);
53 static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
54
55 /* object signals */
56 static void     gtk_tree_view_finalize             (GObject          *object);
57
58 /* widget signals */
59 static void     gtk_tree_view_setup_model          (GtkTreeView      *tree_view);
60 static void     gtk_tree_view_realize              (GtkWidget        *widget);
61 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
62 static void     gtk_tree_view_map                  (GtkWidget        *widget);
63 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
64                                                     GtkRequisition   *requisition);
65 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
66                                                     GtkAllocation    *allocation);
67 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
68                                                     GdkEventExpose   *event);
69 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
70                                                     GdkEventMotion   *event);
71 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
72                                                     GdkEventCrossing *event);
73 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
74                                                     GdkEventCrossing *event);
75 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
76                                                     GdkEventButton   *event);
77 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
78                                                     GdkEventButton   *event);
79 static void     gtk_tree_view_draw_focus           (GtkWidget        *widget);
80 static gint     gtk_tree_view_focus_in             (GtkWidget        *widget,
81                                                     GdkEventFocus    *event);
82 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
83                                                     GdkEventFocus    *event);
84 static gint     gtk_tree_view_focus                (GtkContainer     *container,
85                                                     GtkDirectionType  direction);
86
87 /* container signals */
88 static void     gtk_tree_view_remove               (GtkContainer     *container,
89                                                     GtkWidget        *widget);
90 static void     gtk_tree_view_forall               (GtkContainer     *container,
91                                                     gboolean          include_internals,
92                                                     GtkCallback       callback,
93                                                     gpointer          callback_data);
94
95 /* Source side drag signals */
96 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
97                                             GdkDragContext   *context);
98 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
99                                             GdkDragContext   *context);
100 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
101                                             GdkDragContext   *context,
102                                             GtkSelectionData *selection_data,
103                                             guint             info,
104                                             guint             time);
105 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
106                                             GdkDragContext   *context);
107
108 /* Target side drag signals */
109 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
110                                                   GdkDragContext   *context,
111                                                   guint             time);
112 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
113                                                   GdkDragContext   *context,
114                                                   gint              x,
115                                                   gint              y,
116                                                   guint             time);
117 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
118                                                   GdkDragContext   *context,
119                                                   gint              x,
120                                                   gint              y,
121                                                   guint             time);
122 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
123                                                   GdkDragContext   *context,
124                                                   gint              x,
125                                                   gint              y,
126                                                   GtkSelectionData *selection_data,
127                                                   guint             info,
128                                                   guint             time);
129
130 /* tree_model signals */
131 static void     gtk_tree_view_set_adjustments      (GtkTreeView      *tree_view,
132                                                     GtkAdjustment    *hadj,
133                                                     GtkAdjustment    *vadj);
134 static void     gtk_tree_view_changed              (GtkTreeModel     *model,
135                                                     GtkTreePath      *path,
136                                                     GtkTreeIter      *iter,
137                                                     gpointer          data);
138 static void     gtk_tree_view_inserted             (GtkTreeModel     *model,
139                                                     GtkTreePath      *path,
140                                                     GtkTreeIter      *iter,
141                                                     gpointer          data);
142 static void     gtk_tree_view_child_toggled        (GtkTreeModel     *model,
143                                                     GtkTreePath      *path,
144                                                     GtkTreeIter      *iter,
145                                                     gpointer          data);
146 static void     gtk_tree_view_deleted              (GtkTreeModel     *model,
147                                                     GtkTreePath      *path,
148                                                     gpointer          data);
149
150 /* Internal functions */
151 static void     gtk_tree_view_queue_draw_node      (GtkTreeView      *tree_view,
152                                                     GtkRBTree        *tree,
153                                                     GtkRBNode        *node,
154                                                     GdkRectangle     *clip_rect);
155 static void     gtk_tree_view_draw_arrow           (GtkTreeView      *tree_view,
156                                                     GtkRBTree        *tree,
157                                                     GtkRBNode        *node,
158                                                     gint              x,
159                                                     gint              y);
160 static void     gtk_tree_view_get_arrow_range      (GtkTreeView      *tree_view,
161                                                     gint              *x1,
162                                                     gint              *x2);
163 static gint     gtk_tree_view_new_column_width     (GtkTreeView      *tree_view,
164                                                     gint              i,
165                                                     gint             *x);
166 static void     gtk_tree_view_adjustment_changed   (GtkAdjustment    *adjustment,
167                                                     GtkTreeView      *tree_view);
168 static gint     gtk_tree_view_insert_iter_height   (GtkTreeView      *tree_view,
169                                                     GtkRBTree        *tree,
170                                                     GtkTreeIter      *iter,
171                                                     gint              depth);
172 static void     gtk_tree_view_build_tree           (GtkTreeView      *tree_view,
173                                                     GtkRBTree        *tree,
174                                                     GtkTreeIter      *iter,
175                                                     gint              depth,
176                                                     gboolean          recurse,
177                                                     gboolean          calc_bounds);
178 static void     gtk_tree_view_calc_size            (GtkTreeView      *priv,
179                                                     GtkRBTree        *tree,
180                                                     GtkTreeIter      *iter,
181                                                     gint              depth);
182 static gboolean gtk_tree_view_discover_dirty_iter  (GtkTreeView      *tree_view,
183                                                     GtkTreeIter      *iter,
184                                                     gint              depth,
185                                                     gint             *height);
186 static void     gtk_tree_view_discover_dirty       (GtkTreeView      *tree_view,
187                                                     GtkRBTree        *tree,
188                                                     GtkTreeIter      *iter,
189                                                     gint              depth);
190 static void     gtk_tree_view_check_dirty          (GtkTreeView      *tree_view);
191 static void     gtk_tree_view_create_button        (GtkTreeView      *tree_view,
192                                                     gint              i);
193 static void     gtk_tree_view_create_buttons       (GtkTreeView      *tree_view);
194 static void     gtk_tree_view_button_clicked       (GtkWidget        *widget,
195                                                     gpointer          data);
196 static void     gtk_tree_view_clamp_node_visible   (GtkTreeView      *tree_view,
197                                                     GtkRBTree        *tree,
198                                                     GtkRBNode        *node);
199 static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
200                                                         GdkEventMotion   *event);
201
202 static GtkContainerClass *parent_class = NULL;
203
204
205 /* Class Functions */
206 GtkType
207 gtk_tree_view_get_type (void)
208 {
209   static GtkType tree_view_type = 0;
210
211   if (!tree_view_type)
212     {
213       static const GTypeInfo tree_view_info =
214       {
215         sizeof (GtkTreeViewClass),
216         NULL,           /* base_init */
217         NULL,           /* base_finalize */
218         (GClassInitFunc) gtk_tree_view_class_init,
219         NULL,           /* class_finalize */
220         NULL,           /* class_data */
221         sizeof (GtkTreeView),
222         0,              /* n_preallocs */
223         (GInstanceInitFunc) gtk_tree_view_init
224       };
225
226       tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
227     }
228
229   return tree_view_type;
230 }
231
232 static void
233 gtk_tree_view_class_init (GtkTreeViewClass *class)
234 {
235   GObjectClass *o_class;
236   GtkObjectClass *object_class;
237   GtkWidgetClass *widget_class;
238   GtkContainerClass *container_class;
239
240   o_class = (GObjectClass *) class;
241   object_class = (GtkObjectClass *) class;
242   widget_class = (GtkWidgetClass *) class;
243   container_class = (GtkContainerClass *) class;
244
245   parent_class = g_type_class_peek_parent (class);
246
247   o_class->finalize = gtk_tree_view_finalize;
248
249   widget_class->realize = gtk_tree_view_realize;
250   widget_class->unrealize = gtk_tree_view_unrealize;
251   widget_class->map = gtk_tree_view_map;
252   widget_class->size_request = gtk_tree_view_size_request;
253   widget_class->size_allocate = gtk_tree_view_size_allocate;
254   widget_class->expose_event = gtk_tree_view_expose;
255   widget_class->motion_notify_event = gtk_tree_view_motion;
256   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
257   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
258   widget_class->button_press_event = gtk_tree_view_button_press;
259   widget_class->button_release_event = gtk_tree_view_button_release;
260   widget_class->draw_focus = gtk_tree_view_draw_focus;
261   widget_class->focus_in_event = gtk_tree_view_focus_in;
262   widget_class->focus_out_event = gtk_tree_view_focus_out;
263
264   widget_class->drag_begin = gtk_tree_view_drag_begin;
265   widget_class->drag_end = gtk_tree_view_drag_end;
266   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
267   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
268
269   widget_class->drag_leave = gtk_tree_view_drag_leave;
270   widget_class->drag_motion = gtk_tree_view_drag_motion;
271   widget_class->drag_drop = gtk_tree_view_drag_drop;
272   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
273   
274   container_class->forall = gtk_tree_view_forall;
275   container_class->remove = gtk_tree_view_remove;
276   container_class->focus = gtk_tree_view_focus;
277
278   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
279
280   widget_class->set_scroll_adjustments_signal =
281     gtk_signal_new ("set_scroll_adjustments",
282                     GTK_RUN_LAST,
283                     GTK_CLASS_TYPE (object_class),
284                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
285                     gtk_marshal_VOID__POINTER_POINTER,
286                     GTK_TYPE_NONE, 2,
287                     GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
288 }
289
290 static void
291 gtk_tree_view_init (GtkTreeView *tree_view)
292 {
293   tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
294
295   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
296
297   tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
298   tree_view->priv->tab_offset = TREE_VIEW_EXPANDER_WIDTH;
299   tree_view->priv->n_columns = 0;
300   tree_view->priv->columns = NULL;
301   tree_view->priv->button_pressed_node = NULL;
302   tree_view->priv->button_pressed_tree = NULL;
303   tree_view->priv->prelight_node = NULL;
304   tree_view->priv->header_height = 1;
305   tree_view->priv->x_drag = 0;
306   tree_view->priv->drag_pos = -1;
307   tree_view->priv->selection = NULL;
308   tree_view->priv->anchor = NULL;
309   tree_view->priv->cursor = NULL;
310
311   tree_view->priv->pressed_button = -1;
312   tree_view->priv->press_start_x = -1;
313   tree_view->priv->press_start_y = -1;
314   
315   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
316   _gtk_tree_view_set_size (tree_view, 0, 0);
317 }
318
319
320 /* Object methods
321  */
322
323 static void
324 gtk_tree_view_finalize (GObject *object)
325 {
326   GtkTreeView *tree_view = (GtkTreeView *) object;
327
328   if (tree_view->priv->tree)
329     _gtk_rbtree_free (tree_view->priv->tree);
330
331   if (tree_view->priv->scroll_to_path != NULL)
332     gtk_tree_path_free (tree_view->priv->scroll_to_path);
333
334   if (tree_view->priv->drag_dest_row)
335     gtk_tree_path_free (tree_view->priv->drag_dest_row);
336   
337   g_free (tree_view->priv);
338   if (G_OBJECT_CLASS (parent_class)->finalize)
339     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
340 }
341
342 /* Widget methods
343  */
344
345 static void
346 gtk_tree_view_realize_buttons (GtkTreeView *tree_view)
347 {
348   GList *list;
349   GtkTreeViewColumn *column;
350   GdkWindowAttr attr;
351   guint attributes_mask;
352
353   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
354   g_return_if_fail (tree_view->priv->header_window != NULL);
355
356   attr.window_type = GDK_WINDOW_CHILD;
357   attr.wclass = GDK_INPUT_ONLY;
358   attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
359   attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
360   attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
361   attr.event_mask = (GDK_BUTTON_PRESS_MASK |
362                      GDK_BUTTON_RELEASE_MASK |
363                      GDK_POINTER_MOTION_MASK |
364                      GDK_POINTER_MOTION_HINT_MASK |
365                      GDK_KEY_PRESS_MASK);
366   attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
367   attr.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
368   tree_view->priv->cursor_drag = attr.cursor;
369
370   attr.y = 0;
371   attr.width = TREE_VIEW_DRAG_WIDTH;
372   attr.height = tree_view->priv->header_height;
373
374   for (list = tree_view->priv->columns; list; list = list->next)
375     {
376       column = list->data;
377       if (column->button)
378         {
379           if (column->visible == FALSE)
380             continue;
381           if (column->window != NULL)
382             continue;
383
384           gtk_widget_set_parent_window (column->button,
385                                         tree_view->priv->header_window);
386
387           attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
388           
389           column->window = gdk_window_new (tree_view->priv->header_window,
390                                            &attr, attributes_mask);
391           gdk_window_set_user_data (column->window, tree_view);
392         }
393     }
394 }
395
396 static void
397 gtk_tree_view_realize (GtkWidget *widget)
398 {
399   GList *tmp_list;
400   GtkTreeView *tree_view;
401   GdkGCValues values;
402   GdkWindowAttr attributes;
403   gint attributes_mask;
404
405   g_return_if_fail (widget != NULL);
406   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
407
408   tree_view = GTK_TREE_VIEW (widget);
409
410   if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
411       tree_view->priv->model)
412     gtk_tree_view_setup_model (tree_view);
413
414   gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
415   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
416
417   /* Make the main, clipping window */
418   attributes.window_type = GDK_WINDOW_CHILD;
419   attributes.x = widget->allocation.x;
420   attributes.y = widget->allocation.y;
421   attributes.width = widget->allocation.width;
422   attributes.height = widget->allocation.height;
423   attributes.wclass = GDK_INPUT_OUTPUT;
424   attributes.visual = gtk_widget_get_visual (widget);
425   attributes.colormap = gtk_widget_get_colormap (widget);
426   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
427
428   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
429
430   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
431                                    &attributes, attributes_mask);
432   gdk_window_set_user_data (widget->window, widget);
433
434   /* Make the window for the tree */
435   attributes.x = 0;
436   attributes.y = 0;
437   attributes.width = tree_view->priv->width;
438   attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
439   attributes.event_mask = GDK_EXPOSURE_MASK |
440     GDK_SCROLL_MASK |
441     GDK_POINTER_MOTION_MASK |
442     GDK_ENTER_NOTIFY_MASK |
443     GDK_LEAVE_NOTIFY_MASK |
444     GDK_BUTTON_PRESS_MASK |
445     GDK_BUTTON_RELEASE_MASK |
446     gtk_widget_get_events (widget);
447
448   tree_view->priv->bin_window = gdk_window_new (widget->window,
449                                                 &attributes, attributes_mask);
450   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
451
452   /* Make the column header window */
453   attributes.x = 0;
454   attributes.y = 0;
455   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
456   attributes.height = tree_view->priv->header_height;
457   attributes.event_mask = (GDK_EXPOSURE_MASK |
458                            GDK_SCROLL_MASK |
459                            GDK_BUTTON_PRESS_MASK |
460                            GDK_BUTTON_RELEASE_MASK |
461                            GDK_KEY_PRESS_MASK |
462                            GDK_KEY_RELEASE_MASK) |
463     gtk_widget_get_events (widget);
464
465   tree_view->priv->header_window = gdk_window_new (widget->window,
466                                                    &attributes, attributes_mask);
467   gdk_window_set_user_data (tree_view->priv->header_window, widget);
468
469
470   values.foreground = (widget->style->white.pixel==0 ?
471                        widget->style->black:widget->style->white);
472   values.function = GDK_XOR;
473   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
474   tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
475                                                     &values,
476                                                     GDK_GC_FOREGROUND |
477                                                     GDK_GC_FUNCTION |
478                                                     GDK_GC_SUBWINDOW);
479   /* Add them all up. */
480   widget->style = gtk_style_attach (widget->style, widget->window);
481   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
482   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
483   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
484
485   tmp_list = tree_view->priv->children;
486   while (tmp_list)
487     {
488       GtkTreeViewChild *child = tmp_list->data;
489       tmp_list = tmp_list->next;
490
491       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
492     }
493   gtk_tree_view_realize_buttons (GTK_TREE_VIEW (widget));
494   _gtk_tree_view_set_size (GTK_TREE_VIEW (widget), -1, -1);
495
496   if (tree_view->priv->scroll_to_path != NULL ||
497       tree_view->priv->scroll_to_column != NULL)
498     {
499       gtk_tree_view_scroll_to_cell (tree_view,
500                                     tree_view->priv->scroll_to_path,
501                                     tree_view->priv->scroll_to_column,
502                                     tree_view->priv->scroll_to_row_align,
503                                     tree_view->priv->scroll_to_col_align);
504       if (tree_view->priv->scroll_to_path)
505         {
506           gtk_tree_path_free (tree_view->priv->scroll_to_path);
507           tree_view->priv->scroll_to_path = NULL;
508         }
509       tree_view->priv->scroll_to_column = NULL;
510     }
511 }
512
513 static void
514 gtk_tree_view_unrealize (GtkWidget *widget)
515 {
516   GtkTreeView *tree_view;
517
518   g_return_if_fail (widget != NULL);
519   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
520
521   tree_view = GTK_TREE_VIEW (widget);
522
523   if (tree_view->priv->scroll_timeout != 0)
524     {
525       gtk_timeout_remove (tree_view->priv->scroll_timeout);
526       tree_view->priv->scroll_timeout = 0;
527     }
528
529   if (tree_view->priv->open_dest_timeout != 0)
530     {
531       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
532       tree_view->priv->open_dest_timeout = 0;
533     }
534   
535   /* FIXME where do we clear column->window for each column? */
536   
537   gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
538   gdk_window_destroy (tree_view->priv->bin_window);
539   tree_view->priv->bin_window = NULL;
540
541   gdk_window_set_user_data (tree_view->priv->header_window, NULL);
542   gdk_window_destroy (tree_view->priv->header_window);
543   tree_view->priv->header_window = NULL;
544
545   gdk_cursor_destroy (tree_view->priv->cursor_drag);
546   gdk_gc_destroy (tree_view->priv->xor_gc);  
547   
548   /* GtkWidget::unrealize destroys children and widget->window */
549   
550   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
551     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
552 }
553
554 static void
555 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
556 {
557   GList *list;
558
559   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
560   
561   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
562     {
563       GtkTreeViewColumn *column;
564       
565       for (list = tree_view->priv->columns; list; list = list->next)
566         {
567           column = list->data;
568           if (GTK_WIDGET_VISIBLE (column->button) &&
569               !GTK_WIDGET_MAPPED (column->button))
570             gtk_widget_map (column->button);
571         }
572       for (list = tree_view->priv->columns; list; list = list->next)
573         {
574           column = list->data;
575           if (column->visible == FALSE)
576             continue;
577           if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
578             {
579               gdk_window_raise (column->window);
580               gdk_window_show (column->window);
581             }
582           else
583             gdk_window_hide (column->window);
584         }
585       gdk_window_show (tree_view->priv->header_window);
586     }
587 }
588
589 static void
590 gtk_tree_view_map (GtkWidget *widget)
591 {
592   GList *tmp_list;
593   GtkTreeView *tree_view;
594
595   g_return_if_fail (widget != NULL);
596   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
597
598   tree_view = GTK_TREE_VIEW (widget);
599
600   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
601
602   tmp_list = tree_view->priv->children;
603   while (tmp_list)
604     {
605       GtkTreeViewChild *child = tmp_list->data;
606       tmp_list = tmp_list->next;
607
608       if (GTK_WIDGET_VISIBLE (child->widget))
609         {
610           if (!GTK_WIDGET_MAPPED (child->widget))
611             gtk_widget_map (child->widget);
612         }
613     }
614   gdk_window_show (tree_view->priv->bin_window);
615
616   gtk_tree_view_map_buttons (tree_view);
617   
618   gdk_window_show (widget->window);
619 }
620
621 static void
622 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
623 {
624   GList *list;
625   
626   tree_view->priv->header_height = 1;
627
628   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
629     {
630       for (list = tree_view->priv->columns; list; list = list->next)
631         {
632           GtkRequisition requisition;
633           GtkTreeViewColumn *column;
634           
635           column = list->data;
636           
637           gtk_widget_size_request (column->button, &requisition);
638           
639           gtk_tree_view_column_set_width (column,
640                                           MAX (column->width, requisition.width));
641           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
642         }
643     }
644 }
645
646 static void
647 gtk_tree_view_size_request (GtkWidget      *widget,
648                             GtkRequisition *requisition)
649 {
650   GtkTreeView *tree_view;
651   GList *tmp_list;
652
653   g_return_if_fail (widget != NULL);
654   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
655
656   tree_view = GTK_TREE_VIEW (widget);
657
658   requisition->width = 200;
659   requisition->height = 200;
660
661   tmp_list = tree_view->priv->children;
662
663   while (tmp_list)
664     {
665       GtkTreeViewChild *child = tmp_list->data;
666       GtkRequisition child_requisition;
667
668       tmp_list = tmp_list->next;
669
670       if (GTK_WIDGET_VISIBLE (child->widget))
671         gtk_widget_size_request (child->widget, &child_requisition);
672     }
673
674   gtk_tree_view_size_request_buttons (tree_view);
675 }
676
677 static void
678 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
679 {
680   GtkTreeView *tree_view;
681   GList *list;
682   GList *last_column;
683   GtkTreeViewColumn *column;
684   GtkAllocation allocation;
685   gint width = 0;
686
687   tree_view = GTK_TREE_VIEW (widget);
688
689   allocation.y = 0;
690   allocation.height = tree_view->priv->header_height;
691
692   for (last_column = g_list_last (tree_view->priv->columns);
693        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
694        last_column = last_column->prev)
695     ;
696
697   if (last_column == NULL)
698     return;
699
700   for (list = tree_view->priv->columns; list != last_column; list = list->next)
701     {
702       column = list->data;
703
704       if (!column->visible)
705         continue;
706
707       allocation.x = width;
708       allocation.width = column->width;
709       width += column->width;
710       gtk_widget_size_allocate (column->button, &allocation);
711
712       if (column->window)
713         gdk_window_move_resize (column->window,
714                                 width - TREE_VIEW_DRAG_WIDTH/2, allocation.y,
715                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
716     }
717   column = list->data;
718   allocation.x = width;
719   allocation.width = MAX (widget->allocation.width, tree_view->priv->width) - width;
720   gtk_widget_size_allocate (column->button, &allocation);
721   if (column->window)
722     gdk_window_move_resize (column->window,
723                             allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
724                             0,
725                             TREE_VIEW_DRAG_WIDTH, allocation.height);
726 }
727
728 static void
729 gtk_tree_view_size_allocate (GtkWidget     *widget,
730                              GtkAllocation *allocation)
731 {
732   GList *tmp_list;
733   GtkTreeView *tree_view;
734
735   g_return_if_fail (widget != NULL);
736   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
737
738   widget->allocation = *allocation;
739
740   tree_view = GTK_TREE_VIEW (widget);
741
742   tmp_list = tree_view->priv->children;
743
744   while (tmp_list)
745     {
746       GtkAllocation allocation;
747       GtkRequisition requisition;
748
749       GtkTreeViewChild *child = tmp_list->data;
750       tmp_list = tmp_list->next;
751
752       allocation.x = child->x;
753       allocation.y = child->y;
754       gtk_widget_get_child_requisition (child->widget, &requisition);
755       allocation.width = requisition.width;
756       allocation.height = requisition.height;
757
758       gtk_widget_size_allocate (child->widget, &allocation);
759     }
760
761   if (GTK_WIDGET_REALIZED (widget))
762     {
763       gdk_window_move_resize (widget->window,
764                               allocation->x, allocation->y,
765                               allocation->width, allocation->height);
766       gdk_window_move_resize (tree_view->priv->header_window,
767                               0, 0,
768                               MAX (tree_view->priv->width, allocation->width),
769                               tree_view->priv->header_height);
770     }
771
772   /* FIXME I don't think the invariant that the model must be setup
773    * before touching the buttons is maintained in most of the
774    * rest of the code, e.g. in realize, so something is wrong
775    */
776   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
777     gtk_tree_view_size_allocate_buttons (widget);
778   
779   tree_view->priv->hadjustment->page_size = allocation->width;
780   tree_view->priv->hadjustment->page_increment = allocation->width / 2;
781   tree_view->priv->hadjustment->lower = 0;
782   tree_view->priv->hadjustment->upper = tree_view->priv->width;
783   if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
784     tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
785   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
786
787   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
788   tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
789   tree_view->priv->vadjustment->lower = 0;
790   tree_view->priv->vadjustment->upper = tree_view->priv->height;
791   if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
792     gtk_adjustment_set_value (tree_view->priv->vadjustment,
793                               (gfloat) MAX (tree_view->priv->height - allocation->height, 0));
794   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
795 }
796
797 static void
798 gtk_tree_view_draw_node_focus_rect (GtkWidget   *widget,
799                                     GtkTreePath *path)
800 {
801   GtkTreeView *tree_view;
802   GtkRBTree *tree = NULL;
803   GtkRBNode *node = NULL;
804   gint bin_window_width = 0;
805   
806   g_return_if_fail (widget != NULL);
807   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
808
809   tree_view = GTK_TREE_VIEW (widget);
810
811   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
812
813   if (tree == NULL)
814     return;
815
816   gdk_drawable_get_size (tree_view->priv->bin_window,
817                          &bin_window_width, NULL);
818   
819   /* FIXME need a style function appropriate for this */
820   gdk_draw_rectangle (tree_view->priv->bin_window,
821                       widget->style->fg_gc[GTK_STATE_NORMAL],
822                       FALSE,
823                       0,
824                       _gtk_rbtree_node_find_offset (tree, node) + TREE_VIEW_HEADER_HEIGHT (tree_view),
825                       bin_window_width - 2,
826                       GTK_RBNODE_GET_HEIGHT (node));
827 }
828
829 GdkPixmap*
830 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
831                                     GtkTreePath  *path)
832 {
833   GtkTreeIter   iter;
834   GtkRBTree    *tree;
835   GtkRBNode    *node;
836   GtkCellRenderer *cell;
837   gint i;
838   gint cell_offset;
839   gint max_height;
840   GList *list;
841   GdkRectangle background_area;
842   GtkWidget *widget;
843   gint depth;
844   /* start drawing inside the black outline */
845   gint x = 1, y = 1;
846   GdkDrawable *drawable;
847   gint bin_window_width;
848   
849   widget = GTK_WIDGET (tree_view);
850
851   depth = gtk_tree_path_get_depth (path);
852
853   if (_gtk_tree_view_find_node (tree_view,
854                                 path,
855                                 &tree,
856                                 &node))
857     return NULL;
858
859   if (!gtk_tree_model_get_iter (tree_view->priv->model,
860                                 &iter,
861                                 path))
862     return NULL;
863   
864   max_height = GTK_RBNODE_GET_HEIGHT (node);
865     
866   cell_offset = x;
867
868   background_area.y = y + TREE_VIEW_VERTICAL_SEPARATOR;
869   background_area.height = max_height - TREE_VIEW_VERTICAL_SEPARATOR;
870
871   gdk_drawable_get_size (tree_view->priv->bin_window,
872                          &bin_window_width, NULL);
873   
874   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
875                              bin_window_width + 2,
876                              max_height + 2,
877                              -1);
878
879   gdk_draw_rectangle (drawable,
880                       widget->style->base_gc[GTK_WIDGET_STATE (widget)],
881                       TRUE,
882                       0, 0,
883                       bin_window_width + 2,
884                       max_height + 2);
885
886   gdk_draw_rectangle (drawable,
887                       widget->style->black_gc,
888                       FALSE,
889                       0, 0,
890                       bin_window_width + 1,
891                       max_height + 1);
892   
893   for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
894     {
895       GtkTreeViewColumn *column = list->data;
896       GdkRectangle cell_area;
897       
898       if (!column->visible)
899         continue;
900
901       cell = column->cell;
902       gtk_tree_view_column_set_cell_data (column,
903                                           tree_view->priv->model,
904                                           &iter);
905
906       background_area.x = cell_offset;
907       background_area.width = TREE_VIEW_COLUMN_WIDTH (column);
908
909       cell_area = background_area;
910       
911       if (i == tree_view->priv->expander_column &&
912           TREE_VIEW_DRAW_EXPANDERS(tree_view))
913         {
914           cell_area.x += depth * tree_view->priv->tab_offset;
915           cell_area.width -= depth * tree_view->priv->tab_offset;
916         }
917       
918       gtk_cell_renderer_render (cell,
919                                 drawable,
920                                 widget,
921                                 &background_area,
922                                 &cell_area,
923                                 NULL,
924                                 0);
925       
926       cell_offset += TREE_VIEW_COLUMN_WIDTH (column);
927     }
928
929   return drawable;
930 }
931
932 /* Warning: Very scary function.
933  * Modify at your own risk
934  */
935 static gboolean
936 gtk_tree_view_bin_expose (GtkWidget      *widget,
937                           GdkEventExpose *event)
938 {
939   GtkTreeView *tree_view;
940   GtkTreePath *path;
941   GtkRBTree *tree;
942   GList *list;
943   GtkRBNode *node, *last_node = NULL;
944   GtkRBNode *cursor = NULL;
945   GtkRBTree *cursor_tree = NULL, *last_tree = NULL;
946   GtkRBNode *drag_highlight = NULL;
947   GtkRBTree *drag_highlight_tree = NULL;
948   GtkTreeIter iter;
949   GtkCellRenderer *cell;
950   gint new_y;
951   gint y_offset, x_offset, cell_offset;
952   gint i, max_height;
953   gint depth;
954   GdkRectangle background_area;
955   GdkRectangle cell_area;
956   guint flags;
957   gboolean last_selected;
958   gint highlight_x;
959   gint bin_window_width;
960   
961   g_return_val_if_fail (widget != NULL, FALSE);
962   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
963
964   tree_view = GTK_TREE_VIEW (widget);
965
966   if (tree_view->priv->tree == NULL)
967     return TRUE;
968   
969   gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
970   /* we want to account for a potential HEADER offset.
971    * That is, if the header exists, we want to offset our event by its
972    * height to find the right node.
973    */
974   new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
975   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
976                                        new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
977                                        &tree,
978                                        &node) + new_y - event->area.y;
979   if (node == NULL)
980     return TRUE;
981
982   /* See if the last node was selected */
983   _gtk_rbtree_prev_full (tree, node, &last_tree, &last_node);
984   last_selected = (last_node && GTK_RBNODE_FLAG_SET (last_node, GTK_RBNODE_IS_SELECTED));
985
986   /* find the path for the node */
987   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
988                                    tree,
989                                    node);
990   gtk_tree_model_get_iter (tree_view->priv->model,
991                            &iter,
992                            path);
993   depth = gtk_tree_path_get_depth (path);
994   gtk_tree_path_free (path);
995
996   if (tree_view->priv->cursor)
997     _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor, &cursor_tree, &cursor);
998
999   if (tree_view->priv->drag_dest_row)
1000     _gtk_tree_view_find_node (tree_view, tree_view->priv->drag_dest_row,
1001                               &drag_highlight_tree, &drag_highlight);
1002
1003   gdk_drawable_get_size (tree_view->priv->bin_window,
1004                          &bin_window_width, NULL);
1005   
1006   /* Actually process the expose event.  To do this, we want to
1007    * start at the first node of the event, and walk the tree in
1008    * order, drawing each successive node.
1009    */
1010
1011   do
1012     {
1013       /* Need to think about this more.
1014          if (tree_view->priv->show_expanders)
1015          max_height = MAX (TREE_VIEW_EXPANDER_MIN_HEIGHT, GTK_RBNODE_GET_HEIGHT (node));
1016          else
1017       */
1018       max_height = GTK_RBNODE_GET_HEIGHT (node);
1019
1020       x_offset = -event->area.x;
1021       cell_offset = 0;
1022       highlight_x = 0; /* should match x coord of first cell */
1023       
1024       background_area.y = y_offset + event->area.y + TREE_VIEW_VERTICAL_SEPARATOR;
1025       background_area.height = max_height - TREE_VIEW_VERTICAL_SEPARATOR;
1026       flags = 0;
1027
1028       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
1029         flags |= GTK_CELL_RENDERER_PRELIT;
1030
1031       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1032         {
1033           flags |= GTK_CELL_RENDERER_SELECTED;
1034
1035           /* Draw the selection */
1036           gdk_draw_rectangle (event->window,
1037                               GTK_WIDGET (tree_view)->style->bg_gc [GTK_STATE_SELECTED],
1038                               TRUE,
1039                               event->area.x,
1040                               background_area.y - (last_selected?TREE_VIEW_VERTICAL_SEPARATOR:0),
1041                               event->area.width,
1042                               background_area.height + (last_selected?TREE_VIEW_VERTICAL_SEPARATOR:0));
1043           last_selected = TRUE;
1044         }
1045       else
1046         {
1047           last_selected = FALSE;
1048         }
1049
1050       for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1051         {
1052           GtkTreeViewColumn *column = list->data;
1053
1054           if (!column->visible)
1055             continue;
1056
1057           cell = column->cell;
1058           gtk_tree_view_column_set_cell_data (column,
1059                                               tree_view->priv->model,
1060                                               &iter);
1061
1062           background_area.x = cell_offset;
1063           background_area.width = TREE_VIEW_COLUMN_WIDTH (column);
1064           if (i == tree_view->priv->expander_column &&
1065               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1066             {
1067               cell_area = background_area;
1068               cell_area.x += depth*tree_view->priv->tab_offset;
1069               cell_area.width -= depth*tree_view->priv->tab_offset;
1070
1071               /* If we have an expander column, the highlight underline
1072                * starts with that column, so that it indicates which
1073                * level of the tree we're dropping at.
1074                */
1075               highlight_x = cell_area.x;
1076               
1077               gtk_cell_renderer_render (cell,
1078                                         event->window,
1079                                         widget,
1080                                         &background_area,
1081                                         &cell_area,
1082                                         &event->area,
1083                                         flags);
1084               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
1085                 {
1086                   gint x, y;
1087                   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
1088                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1089                                             tree,
1090                                             node,
1091                                             x, y);
1092                 }
1093             }
1094           else
1095             {
1096               cell_area = background_area;
1097               gtk_cell_renderer_render (cell,
1098                                         event->window,
1099                                         widget,
1100                                         &background_area,
1101                                         &cell_area,
1102                                         &event->area,
1103                                         flags);
1104             }
1105           cell_offset += TREE_VIEW_COLUMN_WIDTH (column);
1106         }
1107
1108       if (node == cursor &&
1109           GTK_WIDGET_HAS_FOCUS (widget))
1110         gtk_tree_view_draw_focus (widget);
1111
1112       if (node == drag_highlight)
1113         {
1114           /* Draw indicator for the drop
1115            */
1116           gint highlight_y = -1;
1117
1118           switch (tree_view->priv->drag_dest_pos)
1119             {
1120             case GTK_TREE_VIEW_DROP_BEFORE:
1121               highlight_y = background_area.y - TREE_VIEW_VERTICAL_SEPARATOR/2;
1122               break;
1123               
1124             case GTK_TREE_VIEW_DROP_AFTER:
1125               highlight_y = background_area.y + background_area.height + TREE_VIEW_VERTICAL_SEPARATOR/2;
1126               break;
1127               
1128             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1129             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1130               gtk_tree_view_draw_node_focus_rect (widget,
1131                                                   tree_view->priv->drag_dest_row);
1132               break;
1133             }
1134
1135           if (highlight_y >= 0)
1136             {
1137               gdk_draw_line (event->window,
1138                              widget->style->black_gc,
1139                              highlight_x,
1140                              highlight_y,
1141                              bin_window_width - highlight_x,
1142                              highlight_y);
1143             }
1144         }
1145       
1146       y_offset += max_height;
1147       if (node->children)
1148         {
1149           GtkTreeIter parent = iter;
1150           gboolean has_child;
1151
1152           tree = node->children;
1153           node = tree->root;
1154           while (node->left != tree->nil)
1155             node = node->left;
1156           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
1157                                                     &iter,
1158                                                     &parent);
1159           cell = gtk_tree_view_get_column (tree_view, 0)->cell;
1160           depth++;
1161
1162           /* Sanity Check! */
1163           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
1164         }
1165       else
1166         {
1167           gboolean done = FALSE;
1168           do
1169             {
1170               node = _gtk_rbtree_next (tree, node);
1171               if (node != NULL)
1172                 {
1173                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
1174                   cell = gtk_tree_view_get_column (tree_view, 0)->cell;
1175                   done = TRUE;
1176
1177                   /* Sanity Check! */
1178                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
1179                 }
1180               else
1181                 {
1182                   GtkTreeIter parent_iter = iter;
1183                   gboolean has_parent;
1184
1185                   node = tree->parent_node;
1186                   tree = tree->parent_tree;
1187                   if (tree == NULL)
1188                     /* we've run out of tree.  It's okay to return though, as
1189                      * we'd only break out of the while loop below. */
1190                     return TRUE;
1191                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
1192                                                            &iter,
1193                                                            &parent_iter);
1194                   depth--;
1195
1196                   /* Sanity check */
1197                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
1198                 }
1199             }
1200           while (!done);
1201         }
1202     }
1203   while (y_offset < event->area.height);
1204
1205   return TRUE;
1206 }
1207
1208 static gboolean
1209 gtk_tree_view_expose (GtkWidget      *widget,
1210                       GdkEventExpose *event)
1211 {
1212   GtkTreeView *tree_view;
1213
1214   g_return_val_if_fail (widget != NULL, FALSE);
1215   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1216
1217   tree_view = GTK_TREE_VIEW (widget);
1218
1219   if (event->window == tree_view->priv->bin_window)
1220     return gtk_tree_view_bin_expose (widget, event);
1221
1222   return TRUE;
1223 }
1224
1225 static gboolean
1226 coords_are_over_arrow (GtkTreeView *tree_view,
1227                        GtkRBTree   *tree,
1228                        GtkRBNode   *node,
1229                        /* these are in tree window coords */
1230                        gint         x,
1231                        gint         y)
1232 {
1233   GdkRectangle arrow;
1234   gint x2;
1235
1236   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1237     return FALSE;
1238   
1239   arrow.y = _gtk_rbtree_node_find_offset (tree, node) + TREE_VIEW_HEADER_HEIGHT (tree_view);  
1240       
1241   arrow.height = GTK_RBNODE_GET_HEIGHT (node);
1242
1243   gtk_tree_view_get_arrow_range (tree_view, &arrow.x, &x2);
1244
1245   arrow.width = x2 - arrow.x;
1246
1247   return (x >= arrow.x &&
1248           x < (arrow.x + arrow.height) &&
1249           y >= arrow.y &&
1250           y < (arrow.y + arrow.height));  
1251 }
1252
1253 static void
1254 do_unprelight (GtkTreeView *tree_view,
1255                /* these are in tree window coords */
1256                gint x,
1257                gint y)
1258 {
1259   gint y1, y2;
1260   
1261   if (tree_view->priv->prelight_node == NULL)
1262     return;
1263   
1264   y1 = _gtk_rbtree_node_find_offset (tree_view->priv->prelight_tree,
1265                                      tree_view->priv->prelight_node) +
1266     TREE_VIEW_HEADER_HEIGHT (tree_view);  
1267       
1268   y2 = y1 + GTK_RBNODE_GET_HEIGHT (tree_view->priv->prelight_node);
1269   
1270   if (tree_view->priv->prelight_node)
1271     GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1272
1273   /* FIXME queue draw on y1-y2 range */
1274   
1275   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1276       !coords_are_over_arrow (tree_view,
1277                               tree_view->priv->prelight_tree,
1278                               tree_view->priv->prelight_node,
1279                               x,
1280                               y))
1281     /* We need to unprelight the old arrow. */
1282     {
1283       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1284       
1285       gtk_tree_view_draw_arrow (tree_view,
1286                                 tree_view->priv->prelight_tree,
1287                                 tree_view->priv->prelight_node,
1288                                 x,
1289                                 y);      
1290
1291     }
1292   
1293   tree_view->priv->prelight_node = NULL;
1294   tree_view->priv->prelight_tree = NULL;
1295
1296   /* FIXME */
1297   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
1298 }
1299
1300 static void
1301 do_prelight (GtkTreeView *tree_view,
1302              GtkRBTree   *tree,
1303              GtkRBNode   *node,
1304              /* these are in tree window coords */
1305              gint         x,
1306              gint         y)
1307 {
1308   if (coords_are_over_arrow (tree_view, tree, node, x, y))
1309     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1310
1311   tree_view->priv->prelight_node = node;
1312   tree_view->priv->prelight_tree = tree;
1313
1314   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1315
1316   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
1317 }
1318
1319 static gboolean
1320 gtk_tree_view_motion (GtkWidget      *widget,
1321                       GdkEventMotion *event)
1322 {
1323   GtkTreeView *tree_view;
1324   GtkRBTree *tree;
1325   GtkRBNode *node;
1326   gint new_y;
1327   
1328   tree_view = (GtkTreeView *) widget;
1329   
1330   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1331     {
1332       gint x;
1333       gint new_width;
1334
1335       if (event->is_hint || event->window != widget->window)
1336         gtk_widget_get_pointer (widget, &x, NULL);
1337       else
1338         x = event->x;
1339
1340       new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos, &x);
1341       if (x != tree_view->priv->x_drag)
1342         {
1343           gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos), new_width);
1344         }
1345
1346       /* FIXME: Do we need to scroll */
1347       _gtk_tree_view_set_size (GTK_TREE_VIEW (widget), -1, tree_view->priv->height);
1348       return FALSE;
1349     }
1350
1351   /* Sanity check it */
1352   if (event->window != tree_view->priv->bin_window)
1353     return FALSE;
1354
1355   if (tree_view->priv->tree == NULL)
1356     return FALSE;
1357
1358   gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
1359
1360   do_unprelight (tree_view, event->x, event->y);  
1361   
1362   new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1363
1364   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
1365                            &tree,
1366                            &node);
1367
1368   if (node == NULL)
1369     return TRUE;
1370
1371   /* If we are currently pressing down a button, we don't want to prelight anything else. */
1372   if ((tree_view->priv->button_pressed_node != NULL) &&
1373       (tree_view->priv->button_pressed_node != node))
1374     return TRUE;
1375
1376
1377   do_prelight (tree_view, tree, node, event->x, new_y);
1378
1379   return TRUE;
1380 }
1381
1382 /* FIXME Is this function necessary? Can I get an enter_notify event
1383  * w/o either an expose event or a mouse motion event?
1384  */
1385 static gboolean
1386 gtk_tree_view_enter_notify (GtkWidget        *widget,
1387                             GdkEventCrossing *event)
1388 {
1389   GtkTreeView *tree_view;
1390   GtkRBTree *tree;
1391   GtkRBNode *node;
1392   gint new_y;
1393
1394   g_return_val_if_fail (widget != NULL, FALSE);
1395   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1396
1397   tree_view = GTK_TREE_VIEW (widget);
1398
1399   /* Sanity check it */
1400   if (event->window != tree_view->priv->bin_window)
1401     return FALSE;
1402
1403   if (tree_view->priv->tree == NULL)
1404     return FALSE;
1405
1406   if ((tree_view->priv->button_pressed_node != NULL) &&
1407       (tree_view->priv->button_pressed_node != node))
1408     return TRUE;
1409
1410   /* find the node internally */
1411   new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1412
1413   _gtk_rbtree_find_offset (tree_view->priv->tree,
1414                            new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
1415                            &tree,
1416                            &node);
1417   
1418   if (node == NULL)
1419     return FALSE;
1420
1421   do_prelight (tree_view, tree, node, event->x, new_y);
1422
1423   return TRUE;
1424 }
1425
1426 static gboolean
1427 gtk_tree_view_leave_notify (GtkWidget        *widget,
1428                             GdkEventCrossing *event)
1429 {
1430   GtkTreeView *tree_view;
1431
1432   g_return_val_if_fail (widget != NULL, FALSE);
1433   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1434
1435   tree_view = GTK_TREE_VIEW (widget);
1436
1437   do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
1438
1439   return TRUE;
1440 }
1441
1442 static gboolean
1443 gtk_tree_view_button_press (GtkWidget      *widget,
1444                             GdkEventButton *event)
1445 {
1446   GtkTreeView *tree_view;
1447   GList *list;
1448   GtkTreeViewColumn *column;
1449   gint i;
1450   GdkRectangle background_area;
1451   GdkRectangle cell_area;
1452
1453   g_return_val_if_fail (widget != NULL, FALSE);
1454   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1455   g_return_val_if_fail (event != NULL, FALSE);
1456
1457   tree_view = GTK_TREE_VIEW (widget);
1458
1459   if (event->window == tree_view->priv->bin_window)
1460     {
1461       GtkRBNode *node;
1462       GtkRBTree *tree;
1463       GtkTreePath *path;
1464       gchar *path_string;
1465       gint depth;
1466       gint new_y;
1467       gint y_offset;
1468
1469       if (!GTK_WIDGET_HAS_FOCUS (widget))
1470         gtk_widget_grab_focus (widget);
1471       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1472
1473       /* are we in an arrow? */
1474       if (tree_view->priv->prelight_node &&
1475           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1476         {
1477           if (event->button == 1)
1478             {
1479               gtk_grab_add (widget);
1480               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1481               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1482               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1483                                         tree_view->priv->prelight_tree,
1484                                         tree_view->priv->prelight_node,
1485                                         event->x,
1486                                         event->y);
1487             }
1488           return TRUE;
1489         }
1490
1491       /* find the node that was clicked */
1492       new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1493       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1494                                            new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
1495                                            &tree,
1496                                            &node) + new_y - (gint)event->y;
1497
1498       if (node == NULL)
1499         /* We clicked in dead space */
1500         return TRUE;
1501
1502       /* Get the path and the node */
1503       path = _gtk_tree_view_find_path (tree_view, tree, node);
1504       depth = gtk_tree_path_get_depth (path);
1505       background_area.y = y_offset + event->y + TREE_VIEW_VERTICAL_SEPARATOR;
1506       background_area.height = GTK_RBNODE_GET_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPARATOR;
1507       background_area.x = 0;
1508       /* Let the cell have a chance at selecting it. */
1509
1510       for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1511         {
1512           GtkTreeViewColumn *column = list->data;
1513           GtkCellRenderer *cell;
1514           GtkTreeIter iter;
1515
1516           if (!column->visible)
1517             continue;
1518
1519           background_area.width = TREE_VIEW_COLUMN_WIDTH (column);
1520           if (i == tree_view->priv->expander_column &&
1521               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1522             {
1523               cell_area = background_area;
1524               cell_area.x += depth*tree_view->priv->tab_offset;
1525               cell_area.width -= depth*tree_view->priv->tab_offset;
1526             }
1527           else
1528             {
1529               cell_area = background_area;
1530             }
1531
1532           cell = column->cell;
1533
1534           if ((background_area.x > (gint) event->x) ||
1535               (background_area.y > (gint) event->y) ||
1536               (background_area.x + background_area.width <= (gint) event->x) ||
1537               (background_area.y + background_area.height <= (gint) event->y))
1538             {
1539               background_area.x += background_area.width;
1540               continue;
1541             }
1542
1543           gtk_tree_model_get_iter (tree_view->priv->model,
1544                                    &iter,
1545                                    path);
1546           gtk_tree_view_column_set_cell_data (column,
1547                                               tree_view->priv->model,
1548                                               &iter);
1549
1550           path_string = gtk_tree_path_to_string (path);
1551           if (gtk_cell_renderer_event (cell,
1552                                        (GdkEvent *)event,
1553                                        widget,
1554                                        path_string,
1555                                        &background_area,
1556                                        &cell_area,
1557                                        0))
1558
1559             {
1560               g_free (path_string);
1561               gtk_tree_path_free (path);
1562               return TRUE;
1563             }
1564           else
1565             {
1566               g_free (path_string);
1567               break;
1568             }
1569         }
1570
1571       /* Save press to possibly begin a drag
1572        */
1573       if (tree_view->priv->pressed_button < 0)
1574         {
1575           tree_view->priv->pressed_button = event->button;
1576           tree_view->priv->press_start_x = event->x;
1577           tree_view->priv->press_start_y = event->y;
1578         }      
1579       
1580       /* Handle the selection */
1581       if (tree_view->priv->selection == NULL)
1582         tree_view->priv->selection =
1583           _gtk_tree_selection_new_with_tree_view (tree_view);
1584
1585       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
1586                                                 node,
1587                                                 tree,
1588                                                 path,
1589                                                 event->state);
1590       gtk_tree_path_free (path);
1591       return TRUE;
1592     }
1593
1594   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1595     {
1596       column = list->data;
1597       if (event->window == column->window &&
1598           column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE &&
1599           column->window)
1600         {
1601           gpointer drag_data;
1602
1603           if (gdk_pointer_grab (column->window, FALSE,
1604                                 GDK_POINTER_MOTION_HINT_MASK |
1605                                 GDK_BUTTON1_MOTION_MASK |
1606                                 GDK_BUTTON_RELEASE_MASK,
1607                                 NULL, NULL, event->time))
1608             return FALSE;
1609
1610           gtk_grab_add (widget);
1611           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1612
1613           /* block attached dnd signal handler */
1614           drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1615           if (drag_data)
1616             gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1617
1618           if (!GTK_WIDGET_HAS_FOCUS (widget))
1619             gtk_widget_grab_focus (widget);
1620
1621           tree_view->priv->drag_pos = i;
1622           tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1623         }
1624     }
1625   return TRUE;
1626 }
1627
1628 static gboolean
1629 gtk_tree_view_button_release (GtkWidget      *widget,
1630                               GdkEventButton *event)
1631 {
1632   GtkTreeView *tree_view;
1633
1634   g_return_val_if_fail (widget != NULL, FALSE);
1635   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1636   g_return_val_if_fail (event != NULL, FALSE);
1637
1638   tree_view = GTK_TREE_VIEW (widget);
1639
1640   if (tree_view->priv->pressed_button == event->button)
1641     tree_view->priv->pressed_button = -1;
1642   
1643   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1644     {
1645       gpointer drag_data;
1646       gint width;
1647       gint x;
1648       gint i;
1649
1650       i = tree_view->priv->drag_pos;
1651       tree_view->priv->drag_pos = -1;
1652
1653       /* unblock attached dnd signal handler */
1654       drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1655       if (drag_data)
1656         gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1657
1658       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1659       gtk_widget_get_pointer (widget, &x, NULL);
1660       gtk_grab_remove (widget);
1661       gdk_pointer_ungrab (event->time);
1662
1663       width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1664       gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1665       return FALSE;
1666     }
1667
1668   if (tree_view->priv->button_pressed_node == NULL)
1669     return FALSE;
1670
1671   if (event->button == 1)
1672     {
1673       gtk_grab_remove (widget);
1674       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1675           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1676         {
1677           GtkTreePath *path;
1678           GtkTreeIter iter;
1679
1680           /* Actually activate the node */
1681           if (tree_view->priv->button_pressed_node->children == NULL)
1682             {
1683               GtkTreeIter child;
1684               path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
1685                                                tree_view->priv->button_pressed_tree,
1686                                                tree_view->priv->button_pressed_node);
1687               tree_view->priv->button_pressed_node->children = _gtk_rbtree_new ();
1688               tree_view->priv->button_pressed_node->children->parent_tree = tree_view->priv->button_pressed_tree;
1689               tree_view->priv->button_pressed_node->children->parent_node = tree_view->priv->button_pressed_node;
1690               gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1691               gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
1692
1693               gtk_tree_view_build_tree (tree_view,
1694                                         tree_view->priv->button_pressed_node->children,
1695                                         &child,
1696                                         gtk_tree_path_get_depth (path) + 1,
1697                                         FALSE,
1698                                         GTK_WIDGET_REALIZED (widget));
1699             }
1700           else
1701             {
1702               path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
1703                                                tree_view->priv->button_pressed_node->children,
1704                                                tree_view->priv->button_pressed_node->children->root);
1705               gtk_tree_model_get_iter (tree_view->priv->model,
1706                                        &iter,
1707                                        path);
1708
1709               gtk_tree_view_discover_dirty (GTK_TREE_VIEW (widget),
1710                                             tree_view->priv->button_pressed_node->children,
1711                                             &iter,
1712                                             gtk_tree_path_get_depth (path));
1713               _gtk_rbtree_remove (tree_view->priv->button_pressed_node->children);
1714             }
1715           gtk_tree_path_free (path);
1716
1717           _gtk_tree_view_set_size (GTK_TREE_VIEW (widget), -1, -1);
1718         }
1719
1720       tree_view->priv->button_pressed_node = NULL;
1721     }
1722
1723   return TRUE;
1724 }
1725
1726
1727 static void
1728 gtk_tree_view_draw_focus (GtkWidget *widget)
1729 {
1730   GtkTreeView *tree_view;
1731
1732   g_return_if_fail (widget != NULL);
1733   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1734
1735   tree_view = GTK_TREE_VIEW (widget);
1736
1737   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
1738     return;
1739   if (tree_view->priv->cursor == NULL)
1740     return;
1741
1742   gtk_tree_view_draw_node_focus_rect (widget, tree_view->priv->cursor);
1743 }
1744
1745
1746 static gint
1747 gtk_tree_view_focus_in (GtkWidget     *widget,
1748                         GdkEventFocus *event)
1749 {
1750   GtkTreeView *tree_view;
1751
1752   g_return_val_if_fail (widget != NULL, FALSE);
1753   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1754   g_return_val_if_fail (event != NULL, FALSE);
1755
1756   tree_view = GTK_TREE_VIEW (widget);
1757
1758   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1759
1760   /* FIXME don't redraw so much */
1761   gtk_widget_queue_draw (widget);
1762
1763   return FALSE;
1764 }
1765
1766
1767 static gint
1768 gtk_tree_view_focus_out (GtkWidget     *widget,
1769                          GdkEventFocus *event)
1770 {
1771   g_return_val_if_fail (widget != NULL, FALSE);
1772   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1773   g_return_val_if_fail (event != NULL, FALSE);
1774
1775   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1776
1777   /* FIXME don't redraw so much */
1778   gtk_widget_queue_draw (widget);
1779
1780   return FALSE;
1781 }
1782
1783 /* FIXME: It would be neat to someday make the headers a seperate widget that
1784  * can be shared between various apps.  Wishful thinking, though...
1785  */
1786 /* Returns TRUE if the focus is within the headers, after the focus operation is
1787  * done
1788  */
1789 static gboolean
1790 gtk_tree_view_header_focus (GtkTreeView        *tree_view,
1791                             GtkDirectionType  dir)
1792 {
1793   GtkWidget *focus_child;
1794   GtkContainer *container;
1795
1796   GList *last_column, *first_column;
1797   GList *tmp_list;
1798
1799   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1800     return FALSE;
1801
1802   focus_child = GTK_CONTAINER (tree_view)->focus_child;
1803   container = GTK_CONTAINER (tree_view);
1804
1805   for (last_column = g_list_last (tree_view->priv->columns);
1806        last_column &&
1807          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
1808          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
1809        last_column = last_column->prev)
1810     ;
1811
1812   for (first_column = tree_view->priv->columns;
1813        first_column &&
1814          !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible) &&
1815          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button);
1816        first_column = first_column->next)
1817     ;
1818
1819   /* no headers are visible, or are focussable.  We can't focus in or out.
1820    * I wonder if focussable is a real word...
1821    */
1822   if (last_column == NULL)
1823     return FALSE;
1824
1825   /* First thing we want to handle is entering and leaving the headers.
1826    */
1827   switch (dir)
1828     {
1829     case GTK_DIR_TAB_BACKWARD:
1830       if (!focus_child)
1831         {
1832           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
1833           gtk_widget_grab_focus (focus_child);
1834           goto cleanup;
1835         }
1836       if (focus_child == GTK_TREE_VIEW_COLUMN (first_column->data)->button)
1837         {
1838           focus_child = NULL;
1839           goto cleanup;
1840         }
1841       break;
1842
1843     case GTK_DIR_TAB_FORWARD:
1844       if (!focus_child)
1845         {
1846           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1847           gtk_widget_grab_focus (focus_child);
1848           goto cleanup;
1849         }
1850       if (focus_child == GTK_TREE_VIEW_COLUMN (last_column->data)->button)
1851         {
1852           focus_child = NULL;
1853           goto cleanup;
1854         }
1855       break;
1856
1857     case GTK_DIR_LEFT:
1858       if (!focus_child)
1859         {
1860           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
1861           gtk_widget_grab_focus (focus_child);
1862           goto cleanup;
1863         }
1864       if (focus_child == GTK_TREE_VIEW_COLUMN (first_column->data)->button)
1865         {
1866           focus_child = NULL;
1867           goto cleanup;
1868         }
1869       break;
1870
1871     case GTK_DIR_RIGHT:
1872       if (!focus_child)
1873         {
1874           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1875           gtk_widget_grab_focus (focus_child);
1876           goto cleanup;
1877         }
1878       if (focus_child == GTK_TREE_VIEW_COLUMN (last_column->data)->button)
1879         {
1880           focus_child = NULL;
1881           goto cleanup;
1882         }
1883       break;
1884
1885     case GTK_DIR_UP:
1886       if (!focus_child)
1887         {
1888           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1889           gtk_widget_grab_focus (focus_child);
1890         }
1891       else
1892         {
1893           focus_child = NULL;
1894         }
1895       goto cleanup;
1896
1897     case GTK_DIR_DOWN:
1898       if (!focus_child)
1899         {
1900           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1901           gtk_widget_grab_focus (focus_child);
1902         }
1903       else
1904         {
1905           focus_child = NULL;
1906         }
1907       goto cleanup;
1908     }
1909
1910   /* We need to move the focus to the next button. */
1911   if (focus_child)
1912     {
1913       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1914         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
1915           {
1916             if (gtk_container_focus (GTK_CONTAINER (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button), dir))
1917               {
1918                 /* The focus moves inside the button. */
1919                 /* This is probably a great example of bad UI */
1920                 goto cleanup;
1921               }
1922             break;
1923           }
1924
1925       /* We need to move the focus among the row of buttons. */
1926       while (tmp_list)
1927         {
1928           GtkTreeViewColumn *column;
1929
1930           if (dir == GTK_DIR_RIGHT || dir == GTK_DIR_TAB_FORWARD)
1931             tmp_list = tmp_list->next;
1932           else
1933             tmp_list = tmp_list->prev;
1934
1935           if (tmp_list == NULL)
1936             {
1937               g_warning ("Internal button not found");
1938               goto cleanup;
1939             }
1940           column = tmp_list->data;
1941           if (column->button &&
1942               column->visible &&
1943               GTK_WIDGET_CAN_FOCUS (column->button))
1944             {
1945               focus_child = column->button;
1946               gtk_widget_grab_focus (column->button);
1947               break;
1948             }
1949         }
1950     }
1951
1952  cleanup:
1953   /* if focus child is non-null, we assume it's been set to the current focus child
1954    */
1955   if (focus_child)
1956     {
1957       /* If the following isn't true, then the view is smaller then the scrollpane.
1958        */
1959       if ((focus_child->allocation.x + focus_child->allocation.width) <=
1960           (tree_view->priv->hadjustment->upper))
1961         {
1962           /* Scroll to the button, if needed */
1963           if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
1964               (focus_child->allocation.x + focus_child->allocation.width))
1965             gtk_adjustment_set_value (tree_view->priv->hadjustment,
1966                                       focus_child->allocation.x + focus_child->allocation.width -
1967                                       tree_view->priv->hadjustment->page_size);
1968           else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
1969             gtk_adjustment_set_value (tree_view->priv->hadjustment,
1970                                       focus_child->allocation.x);
1971         }
1972     }
1973
1974   return (focus_child != NULL);
1975 }
1976
1977 /* WARNING: Scary function */
1978 static gint
1979 gtk_tree_view_focus (GtkContainer     *container,
1980                      GtkDirectionType  direction)
1981 {
1982   GtkTreeView *tree_view;
1983   GtkWidget *focus_child;
1984   GdkEvent *event;
1985   GtkRBTree *cursor_tree;
1986   GtkRBNode *cursor_node;
1987
1988   g_return_val_if_fail (container != NULL, FALSE);
1989   g_return_val_if_fail (GTK_IS_TREE_VIEW (container), FALSE);
1990   g_return_val_if_fail (GTK_WIDGET_VISIBLE (container), FALSE);
1991
1992   tree_view = GTK_TREE_VIEW (container);
1993
1994   if (!GTK_WIDGET_IS_SENSITIVE (container))
1995     return FALSE;
1996   if (tree_view->priv->tree == NULL)
1997     return FALSE;
1998
1999   focus_child = container->focus_child;
2000
2001   /* Case 1.  Headers have focus. */
2002   if (focus_child)
2003     {
2004       switch (direction)
2005         {
2006         case GTK_DIR_LEFT:
2007         case GTK_DIR_TAB_BACKWARD:
2008           return (gtk_tree_view_header_focus (tree_view, direction));
2009         case GTK_DIR_UP:
2010           return FALSE;
2011         case GTK_DIR_TAB_FORWARD:
2012         case GTK_DIR_RIGHT:
2013         case GTK_DIR_DOWN:
2014           if (direction != GTK_DIR_DOWN)
2015             {
2016               if (gtk_tree_view_header_focus (tree_view, direction))
2017                 return TRUE;
2018             }
2019           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2020           gtk_widget_grab_focus (GTK_WIDGET (container));
2021
2022           if (tree_view->priv->selection == NULL)
2023             tree_view->priv->selection =
2024               _gtk_tree_selection_new_with_tree_view (tree_view);
2025
2026           /* if there is no keyboard focus yet, we select the first node
2027            */
2028           if (tree_view->priv->cursor == NULL)
2029             tree_view->priv->cursor = gtk_tree_path_new_root ();
2030
2031           gtk_tree_selection_select_path (tree_view->priv->selection,
2032                                           tree_view->priv->cursor);
2033           /* FIXME make this more efficient */
2034           gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2035           return TRUE;
2036         }
2037     }
2038
2039   /* Case 2. We don't have focus at all. */
2040   if (!GTK_WIDGET_HAS_FOCUS (container))
2041     {
2042       if ((direction == GTK_DIR_TAB_FORWARD) ||
2043           (direction == GTK_DIR_RIGHT) ||
2044           (direction == GTK_DIR_DOWN))
2045         {
2046           if (gtk_tree_view_header_focus (tree_view, direction))
2047             return TRUE;
2048         }
2049
2050       /* The headers didn't want the focus, so we take it. */
2051       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2052       gtk_widget_grab_focus (GTK_WIDGET (container));
2053
2054       if (tree_view->priv->selection == NULL)
2055         tree_view->priv->selection =
2056           _gtk_tree_selection_new_with_tree_view (tree_view);
2057
2058       if (tree_view->priv->cursor == NULL)
2059         tree_view->priv->cursor = gtk_tree_path_new_root ();
2060
2061       gtk_tree_selection_select_path (tree_view->priv->selection,
2062                                       tree_view->priv->cursor);
2063       /* FIXME make this more efficient */
2064       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2065       return TRUE;
2066     }
2067
2068   /* Case 3. We have focus already, but no cursor.  We pick the first one
2069    * and run with it. */
2070   if (tree_view->priv->cursor == NULL)
2071     {
2072       /* We lost our cursor somehow.  Arbitrarily select the first node, and
2073        * return
2074        */
2075       tree_view->priv->cursor = gtk_tree_path_new_root ();
2076
2077       gtk_tree_selection_select_path (tree_view->priv->selection,
2078                                       tree_view->priv->cursor);
2079       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2080                                 0.0);
2081       /* FIXME make this more efficient */
2082       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2083       return TRUE;
2084     }
2085
2086
2087   /* Case 3. We have focus already.  Move the cursor. */
2088   if (direction == GTK_DIR_LEFT)
2089     {
2090       gfloat val;
2091       val = tree_view->priv->hadjustment->value - tree_view->priv->hadjustment->page_size/2;
2092       val = MAX (val, 0.0);
2093       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
2094       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2095       return TRUE;
2096     }
2097   if (direction == GTK_DIR_RIGHT)
2098     {
2099       gfloat val;
2100       val = tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size/2;
2101       val = MIN (tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size, val);
2102       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
2103       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2104       return TRUE;
2105     }
2106   cursor_tree = NULL;
2107   cursor_node = NULL;
2108
2109   _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor,
2110                             &cursor_tree,
2111                             &cursor_node);
2112   switch (direction)
2113     {
2114     case GTK_DIR_TAB_BACKWARD:
2115     case GTK_DIR_UP:
2116       _gtk_rbtree_prev_full (cursor_tree,
2117                              cursor_node,
2118                              &cursor_tree,
2119                              &cursor_node);
2120       break;
2121     case GTK_DIR_TAB_FORWARD:
2122     case GTK_DIR_DOWN:
2123       _gtk_rbtree_next_full (cursor_tree,
2124                              cursor_node,
2125                              &cursor_tree,
2126                              &cursor_node);
2127       break;
2128     default:
2129       break;
2130     }
2131
2132   if (cursor_node)
2133     {
2134       GdkModifierType state = 0;
2135
2136       event = gtk_get_current_event ();
2137       if (event)
2138         gdk_event_get_state (event, &state);
2139
2140       if (event)
2141         gdk_event_free (event);
2142       gtk_tree_path_free (tree_view->priv->cursor);
2143
2144       tree_view->priv->cursor = _gtk_tree_view_find_path (tree_view,
2145                                                           cursor_tree,
2146                                                           cursor_node);
2147       if (tree_view->priv->cursor)
2148         _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
2149                                                   cursor_node,
2150                                                   cursor_tree,
2151                                                   tree_view->priv->cursor,
2152                                                   state);
2153       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
2154       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2155       /* FIXME make this more efficient */
2156       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2157       return TRUE;
2158     }
2159
2160   /* At this point, we've progressed beyond the edge of the rows. */
2161
2162   if ((direction == GTK_DIR_LEFT) ||
2163       (direction == GTK_DIR_TAB_BACKWARD) ||
2164       (direction == GTK_DIR_UP))
2165     /* We can't go back anymore.  Try the headers */
2166     return (gtk_tree_view_header_focus (tree_view, direction));
2167
2168   /* we've reached the end of the tree.  Go on. */
2169   return FALSE;
2170 }
2171
2172 /* Container method
2173  */
2174 static void
2175 gtk_tree_view_remove (GtkContainer *container,
2176                       GtkWidget    *widget)
2177 {
2178   GtkTreeView *tree_view;
2179   GtkTreeViewChild *child = NULL;
2180   GList *tmp_list;
2181
2182   g_return_if_fail (container != NULL);
2183   g_return_if_fail (GTK_IS_TREE_VIEW (container));
2184
2185   tree_view = GTK_TREE_VIEW (container);
2186
2187   tmp_list = tree_view->priv->children;
2188   while (tmp_list)
2189     {
2190       child = tmp_list->data;
2191       if (child->widget == widget)
2192         break;
2193       tmp_list = tmp_list->next;
2194     }
2195
2196   if (tmp_list)
2197     {
2198       gtk_widget_unparent (widget);
2199
2200       tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
2201       g_list_free_1 (tmp_list);
2202       g_free (child);
2203     }
2204 }
2205
2206 static void
2207 gtk_tree_view_forall (GtkContainer *container,
2208                       gboolean      include_internals,
2209                       GtkCallback   callback,
2210                       gpointer      callback_data)
2211 {
2212   GtkTreeView *tree_view;
2213   GtkTreeViewChild *child = NULL;
2214   GtkTreeViewColumn *column;
2215   GList *tmp_list;
2216
2217   g_return_if_fail (container != NULL);
2218   g_return_if_fail (GTK_IS_TREE_VIEW (container));
2219   g_return_if_fail (callback != NULL);
2220
2221   tree_view = GTK_TREE_VIEW (container);
2222
2223   tmp_list = tree_view->priv->children;
2224   while (tmp_list)
2225     {
2226       child = tmp_list->data;
2227       tmp_list = tmp_list->next;
2228
2229       (* callback) (child->widget, callback_data);
2230     }
2231   if (include_internals == FALSE)
2232     return;
2233
2234   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2235     {
2236       column = tmp_list->data;
2237       if (column->button)
2238         (* callback) (column->button, callback_data);
2239     }
2240 }
2241
2242 /* TreeModel Callbacks
2243  */
2244
2245 static void
2246 gtk_tree_view_changed (GtkTreeModel *model,
2247                        GtkTreePath  *path,
2248                        GtkTreeIter  *iter,
2249                        gpointer      data)
2250 {
2251   GtkTreeView *tree_view = (GtkTreeView *)data;
2252   GtkRBTree *tree;
2253   GtkRBNode *node;
2254   gint height;
2255   gboolean dirty_marked;
2256
2257   g_return_if_fail (path != NULL || iter != NULL);
2258
2259   if (path == NULL)
2260     path = gtk_tree_model_get_path (model, iter);
2261   else if (iter == NULL)
2262     gtk_tree_model_get_iter (model, iter, path);
2263
2264   if (_gtk_tree_view_find_node (tree_view,
2265                                 path,
2266                                 &tree,
2267                                 &node))
2268     /* We aren't actually showing the node */
2269     return;
2270
2271   dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
2272                                                     iter,
2273                                                     gtk_tree_path_get_depth (path),
2274                                                     &height);
2275
2276   if (GTK_RBNODE_GET_HEIGHT (node) != height + TREE_VIEW_VERTICAL_SEPARATOR)
2277     {
2278       _gtk_rbtree_node_set_height (tree, node, height + TREE_VIEW_VERTICAL_SEPARATOR);
2279       gtk_widget_queue_resize (GTK_WIDGET (data));
2280       return;
2281     }
2282   if (dirty_marked)
2283     gtk_widget_queue_resize (GTK_WIDGET (data));
2284   else
2285     {
2286       /* FIXME: just redraw the node */
2287       gtk_widget_queue_draw (GTK_WIDGET (data));
2288     }
2289 }
2290
2291 static void
2292 gtk_tree_view_inserted (GtkTreeModel *model,
2293                         GtkTreePath  *path,
2294                         GtkTreeIter  *iter,
2295                         gpointer      data)
2296 {
2297   GtkTreeView *tree_view = (GtkTreeView *) data;
2298   gint *indices;
2299   GtkRBTree *tmptree, *tree;
2300   GtkRBNode *tmpnode = NULL;
2301   gint max_height;
2302   gint depth;
2303   gint i = 0;
2304
2305   tmptree = tree = tree_view->priv->tree;
2306   g_return_if_fail (path != NULL || iter != NULL);
2307
2308   if (path == NULL)
2309     path = gtk_tree_model_get_path (model, iter);
2310   else if (iter == NULL)
2311     gtk_tree_model_get_iter (model, iter, path);
2312
2313   depth = gtk_tree_path_get_depth (path);
2314   indices = gtk_tree_path_get_indices (path);
2315
2316   /* First, find the parent tree */
2317   while (i < depth - 1)
2318     {
2319       if (tmptree == NULL)
2320         {
2321           /* We aren't showing the node */
2322           return;
2323         }
2324
2325       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
2326       if (tmpnode == NULL)
2327         {
2328           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
2329                      "This possibly means that a GtkTreeModel inserted a child node\n" \
2330                      "before the parent was inserted.");
2331           return;
2332         }
2333       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
2334         {
2335           /* FIXME enforce correct behavior on model, probably */
2336           /* In theory, the model should have emitted child_toggled here.  We
2337            * try to catch it anyway, just to be safe, in case the model hasn't.
2338            */
2339           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
2340                                                            tree,
2341                                                            tmpnode);
2342           gtk_tree_view_child_toggled (model, tmppath, NULL, data);
2343           gtk_tree_path_free (tmppath);
2344           return;
2345         }
2346
2347       tmptree = tmpnode->children;
2348       tree = tmptree;
2349       i++;
2350     }
2351
2352   if (tree == NULL)
2353     return;
2354
2355   /* next, update the selection */
2356   if (tree_view->priv->anchor)
2357     {
2358       gint *select_indices = gtk_tree_path_get_indices (tree_view->priv->anchor);
2359       gint select_depth = gtk_tree_path_get_depth (tree_view->priv->anchor);
2360
2361       for (i = 0; i < depth && i < select_depth; i++)
2362         {
2363           if (indices[i] < select_indices[i])
2364             {
2365               select_indices[i]++;
2366               break;
2367             }
2368           else if (indices[i] > select_indices[i])
2369             break;
2370           else if (i == depth - 1)
2371             {
2372               select_indices[i]++;
2373               break;
2374             }
2375         }
2376     }
2377
2378   /* ref the node */
2379   gtk_tree_model_ref_iter (tree_view->priv->model, iter);
2380   max_height = gtk_tree_view_insert_iter_height (tree_view,
2381                                                  tree,
2382                                                  iter,
2383                                                  depth);
2384   if (indices[depth - 1] == 0)
2385     {
2386       tmpnode = _gtk_rbtree_find_count (tree, 1);
2387       _gtk_rbtree_insert_before (tree, tmpnode, max_height);
2388     }
2389   else
2390     {
2391       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
2392       _gtk_rbtree_insert_after (tree, tmpnode, max_height);
2393     }
2394
2395   _gtk_tree_view_set_size (tree_view, -1, tree_view->priv->height + max_height);
2396 }
2397
2398 static void
2399 gtk_tree_view_child_toggled (GtkTreeModel *model,
2400                              GtkTreePath  *path,
2401                              GtkTreeIter  *iter,
2402                              gpointer      data)
2403 {
2404   GtkTreeView *tree_view = (GtkTreeView *)data;
2405   GtkTreeIter real_iter;
2406   gboolean has_child;
2407   GtkRBTree *tree;
2408   GtkRBNode *node;
2409
2410   g_return_if_fail (path != NULL || iter != NULL);
2411
2412   if (iter)
2413     real_iter = *iter;
2414
2415   if (path == NULL)
2416     path = gtk_tree_model_get_path (model, iter);
2417   else if (iter == NULL)
2418     gtk_tree_model_get_iter (model, &real_iter, path);
2419
2420   if (_gtk_tree_view_find_node (tree_view,
2421                                 path,
2422                                 &tree,
2423                                 &node))
2424     /* We aren't actually showing the node */
2425     return;
2426
2427   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
2428   /* Sanity check.
2429    */
2430   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
2431     return;
2432
2433   if (has_child)
2434     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
2435   else
2436     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
2437
2438   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
2439     {
2440       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2441       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
2442         {
2443           GList *list;
2444           for (list = tree_view->priv->columns; list; list = list->next)
2445             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
2446               {
2447                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
2448                 break;
2449               }
2450         }
2451       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
2452     }
2453   else
2454     {
2455       /* FIXME: Just redraw the node */
2456       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2457     }
2458 }
2459
2460 static void
2461 gtk_tree_view_deleted (GtkTreeModel *model,
2462                        GtkTreePath  *path,
2463                        gpointer      data)
2464 {
2465   GtkTreeView *tree_view = (GtkTreeView *)data;
2466   GtkRBTree *tree;
2467   GtkRBNode *node;
2468   GList *list;
2469
2470   g_return_if_fail (path != NULL);
2471
2472   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
2473     return;
2474
2475   /* next, update the selection */
2476   if (tree_view->priv->anchor)
2477     {
2478       gint i;
2479       gint depth = gtk_tree_path_get_depth (path);
2480       gint *indices = gtk_tree_path_get_indices (path);
2481       gint select_depth = gtk_tree_path_get_depth (tree_view->priv->anchor);
2482       gint *select_indices = gtk_tree_path_get_indices (tree_view->priv->anchor);
2483
2484       if (gtk_tree_path_compare (path, tree_view->priv->anchor) == 0)
2485         {
2486           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) &&
2487               tree_view->priv->selection)
2488             gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->selection),
2489                                      "selection_changed");
2490         }
2491       else
2492         {
2493           for (i = 0; i < depth && i < select_depth; i++)
2494             {
2495               if (indices[i] < select_indices[i])
2496                 {
2497                   select_indices[i] = MAX (select_indices[i], 0);
2498                   break;
2499                 }
2500               else if (indices[i] > select_indices[i])
2501                 break;
2502               else if (i == depth - 1)
2503                 {
2504                   select_indices[i] = MAX (select_indices[i], 0);
2505                   break;
2506                 }
2507             }
2508         }
2509     }
2510
2511   for (list = tree_view->priv->columns; list; list = list->next)
2512     if (((GtkTreeViewColumn *)list->data)->visible &&
2513         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2514       ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
2515
2516   if (tree->root->count == 1)
2517     _gtk_rbtree_remove (tree);
2518   else
2519     _gtk_rbtree_remove_node (tree, node);
2520
2521   _gtk_tree_view_set_size (GTK_TREE_VIEW (data), -1, -1);
2522 }
2523
2524 /* Internal tree functions */
2525 static gint
2526 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
2527                                   GtkRBTree   *tree,
2528                                   GtkTreeIter *iter,
2529                                   gint         depth)
2530 {
2531   GtkTreeViewColumn *column;
2532   GtkCellRenderer *cell;
2533   GList *list;
2534   gint max_height = 0;
2535   gint i;
2536
2537   i = 0;
2538   
2539   /* do stuff with node */
2540   for (list = tree_view->priv->columns; list; list = list->next)
2541     {
2542       gint height = 0, width = 0;
2543       column = list->data;
2544
2545       if (!column->visible)
2546         continue;
2547
2548       if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2549         {
2550           ++i;
2551           continue;
2552         }
2553
2554       cell = column->cell;
2555       gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
2556
2557       gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, &height);
2558       max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPARATOR + height);
2559
2560       if (i == tree_view->priv->expander_column &&
2561           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2562         gtk_tree_view_column_set_width (column,
2563                                         MAX (column->width, depth * tree_view->priv->tab_offset + width));
2564       else
2565         gtk_tree_view_column_set_width (column,
2566                                         MAX (column->width, width));
2567
2568       ++i;
2569     }
2570   return max_height;
2571 }
2572
2573 static void
2574 gtk_tree_view_build_tree (GtkTreeView *tree_view,
2575                           GtkRBTree   *tree,
2576                           GtkTreeIter *iter,
2577                           gint         depth,
2578                           gboolean     recurse,
2579                           gboolean     calc_bounds)
2580 {
2581   GtkRBNode *temp = NULL;
2582   gint max_height;
2583
2584   do
2585     {
2586       max_height = 0;
2587       if (calc_bounds)
2588         max_height = gtk_tree_view_insert_iter_height (tree_view,
2589                                                        tree,
2590                                                        iter,
2591                                                        depth);
2592
2593       gtk_tree_model_ref_iter (tree_view->priv->model, iter);
2594       temp = _gtk_rbtree_insert_after (tree, temp, max_height);
2595       if (recurse)
2596         {
2597           GtkTreeIter child;
2598
2599           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
2600             {
2601               temp->children = _gtk_rbtree_new ();
2602               temp->children->parent_tree = tree;
2603               temp->children->parent_node = temp;
2604               gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
2605             }
2606         }
2607       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
2608         {
2609           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
2610             temp->flags ^= GTK_RBNODE_IS_PARENT;
2611           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2612         }
2613     }
2614   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
2615 }
2616
2617 static void
2618 gtk_tree_view_calc_size (GtkTreeView *tree_view,
2619                          GtkRBTree   *tree,
2620                          GtkTreeIter *iter,
2621                          gint         depth)
2622 {
2623   GtkRBNode *temp;
2624   GtkTreeIter child;
2625   GtkCellRenderer *cell;
2626   GList *list;
2627   GtkTreeViewColumn *column;
2628   gint max_height;
2629   gint i;
2630
2631   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
2632
2633   temp = tree->root;
2634   while (temp->left != tree->nil)
2635     temp = temp->left;
2636
2637   do
2638     {
2639       max_height = 0;
2640       /* Do stuff with node */
2641       for (list = tree_view->priv->columns, i = 0; i < tree_view->priv->n_columns; list = list->next, i++)
2642         {
2643           gint height = 0, width = 0;
2644           column = list->data;
2645
2646           if (!column->visible)
2647             continue;
2648
2649           gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
2650           cell = column->cell;
2651           gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, &height);
2652           max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPARATOR + height);
2653
2654           /* FIXME: I'm getting the width of all nodes here. )-: */
2655           if (column->dirty == FALSE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2656             continue;
2657
2658           if (i == tree_view->priv->expander_column &&
2659               TREE_VIEW_DRAW_EXPANDERS (tree_view))
2660             gtk_tree_view_column_set_width (column,
2661                                             MAX (column->width, depth * tree_view->priv->tab_offset + width));
2662           else
2663             gtk_tree_view_column_set_width (column, MAX (column->width, width));
2664         }
2665       _gtk_rbtree_node_set_height (tree, temp, max_height);
2666       if (temp->children != NULL &&
2667           gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
2668         gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
2669       temp = _gtk_rbtree_next (tree, temp);
2670     }
2671   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
2672 }
2673
2674 static gboolean
2675 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
2676                                    GtkTreeIter *iter,
2677                                    gint         depth,
2678                                    gint        *height)
2679 {
2680   GtkCellRenderer *cell;
2681   GtkTreeViewColumn *column;
2682   GList *list;
2683   gint i;
2684   gint retval = FALSE;
2685   gint tmpheight;
2686
2687   if (height)
2688     *height = 0;
2689
2690   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2691     {
2692       gint width;
2693       column = list->data;
2694       if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2695         continue;
2696       if (!column->visible)
2697         continue;
2698
2699       cell = column->cell;
2700       gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
2701
2702       if (height)
2703         {
2704           gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, &tmpheight);
2705           *height = MAX (*height, tmpheight);
2706         }
2707       else
2708         {
2709           gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, NULL);
2710         }
2711       if (i == tree_view->priv->expander_column &&
2712           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2713         {
2714           if (depth * tree_view->priv->tab_offset + width > column->width)
2715             {
2716               column->dirty = TRUE;
2717               retval = TRUE;
2718             }
2719         }
2720       else
2721         {
2722           if (width > column->width)
2723             {
2724               column->dirty = TRUE;
2725               retval = TRUE;
2726             }
2727         }
2728     }
2729
2730   return retval;
2731 }
2732
2733 static void
2734 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
2735                               GtkRBTree   *tree,
2736                               GtkTreeIter *iter,
2737                               gint         depth)
2738 {
2739   GtkRBNode *temp = tree->root;
2740   GtkTreeViewColumn *column;
2741   GList *list;
2742   GtkTreeIter child;
2743   gboolean is_all_dirty;
2744
2745   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
2746
2747   while (temp->left != tree->nil)
2748     temp = temp->left;
2749
2750   do
2751     {
2752       is_all_dirty = TRUE;
2753       for (list = tree_view->priv->columns; list; list = list->next)
2754         {
2755           column = list->data;
2756           if (column->dirty == FALSE)
2757             {
2758               is_all_dirty = FALSE;
2759               break;
2760             }
2761         }
2762
2763       if (is_all_dirty)
2764         return;
2765
2766       gtk_tree_view_discover_dirty_iter (tree_view,
2767                                          iter,
2768                                          depth,
2769                                          FALSE);
2770       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
2771           temp->children != NULL)
2772         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
2773       temp = _gtk_rbtree_next (tree, temp);
2774     }
2775   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
2776 }
2777
2778
2779 static void
2780 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
2781 {
2782   GtkTreePath *path;
2783   gboolean dirty = FALSE;
2784   GList *list;
2785   GtkTreeViewColumn *column;
2786   GtkTreeIter iter;
2787   
2788   for (list = tree_view->priv->columns; list; list = list->next)
2789     {
2790       column = list->data;
2791       if (column->dirty)
2792         {
2793           dirty = TRUE;
2794           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2795             {
2796               gtk_tree_view_column_set_width (column, MAX (column->button->requisition.width, 1));
2797             }
2798         }
2799     }
2800   if (dirty == FALSE)
2801     return;
2802
2803   path = gtk_tree_path_new_root ();
2804   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
2805     {
2806       gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
2807       _gtk_tree_view_set_size (tree_view, -1, -1);
2808     }
2809       
2810   gtk_tree_path_free (path);
2811   
2812   for (list = tree_view->priv->columns; list; list = list->next)
2813     {
2814       column = list->data;
2815       column->dirty = FALSE;
2816     }
2817 }
2818
2819 static void
2820 gtk_tree_view_create_button (GtkTreeView *tree_view,
2821                              gint         i)
2822 {
2823   GtkWidget *button;
2824   GtkTreeViewColumn *column;
2825
2826   column = g_list_nth (tree_view->priv->columns, i)->data;
2827   gtk_widget_push_composite_child ();
2828   button = column->button = gtk_button_new ();
2829   gtk_widget_pop_composite_child ();
2830
2831   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
2832
2833   gtk_signal_connect (GTK_OBJECT (button), "clicked",
2834                       (GtkSignalFunc) gtk_tree_view_button_clicked,
2835                       (gpointer) tree_view);
2836
2837   gtk_widget_show (button);
2838 }
2839
2840 static void
2841 gtk_tree_view_create_buttons (GtkTreeView *tree_view)
2842 {
2843   GtkWidget *alignment;
2844   GtkWidget *label;
2845   GList *list;
2846   GtkTreeViewColumn *column;
2847   gint i;
2848
2849   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2850     {
2851       column = list->data;
2852
2853       if (column->button != NULL)
2854         continue;
2855
2856       gtk_tree_view_create_button (tree_view, i);
2857       switch (column->justification)
2858         {
2859         case GTK_JUSTIFY_LEFT:
2860           alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
2861           break;
2862         case GTK_JUSTIFY_RIGHT:
2863           alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
2864           break;
2865         case GTK_JUSTIFY_CENTER:
2866           alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
2867           break;
2868         case GTK_JUSTIFY_FILL:
2869         default:
2870           alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
2871           break;
2872         }
2873
2874       if (column->child)
2875         label = column->child;
2876       else
2877         {
2878           label = gtk_label_new (column->title);
2879           gtk_widget_show (label);
2880         }
2881
2882       gtk_container_add (GTK_CONTAINER (alignment), label);
2883       gtk_container_add (GTK_CONTAINER (column->button), alignment);
2884       
2885       gtk_widget_show (alignment);
2886     }
2887
2888   gtk_tree_view_size_request_buttons (tree_view);
2889   
2890   if (GTK_WIDGET_REALIZED (tree_view))
2891     gtk_tree_view_realize_buttons (tree_view);
2892
2893   if (GTK_WIDGET_MAPPED (tree_view))
2894     gtk_tree_view_map_buttons (tree_view);  
2895 }
2896
2897 static void
2898 gtk_tree_view_button_clicked (GtkWidget *widget,
2899                               gpointer   data)
2900 {
2901   GList *list;
2902   GtkTreeView *tree_view;
2903
2904   g_return_if_fail (widget != NULL);
2905   g_return_if_fail (GTK_IS_TREE_VIEW (data));
2906
2907   tree_view = GTK_TREE_VIEW (data);
2908
2909   /* find the column whose button was pressed */
2910   for (list = tree_view->priv->columns; list; list = list->next)
2911     if (GTK_TREE_VIEW_COLUMN (list->data)->button == widget)
2912       break;
2913
2914   if (list)
2915     gtk_tree_view_column_clicked (GTK_TREE_VIEW_COLUMN (list->data));
2916 }
2917
2918 /* Make sure the node is visible vertically */
2919 static void
2920 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
2921                                   GtkRBTree   *tree,
2922                                   GtkRBNode   *node)
2923 {
2924   gint offset;
2925
2926   offset = _gtk_rbtree_node_find_offset (tree, node);
2927
2928   /* we reverse the order, b/c in the unusual case of the
2929    * node's height being taller then the visible area, we'd rather
2930    * have the node flush to the top
2931    */
2932   if (offset + GTK_RBNODE_GET_HEIGHT (node) >
2933       tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
2934     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2935                               offset + GTK_RBNODE_GET_HEIGHT (node) -
2936                               tree_view->priv->vadjustment->page_size);
2937   if (offset < tree_view->priv->vadjustment->value)
2938     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2939                               offset);
2940 }
2941
2942 /* This function could be more efficient.
2943  * I'll optimize it if profiling seems to imply that
2944  * it's important
2945  */
2946 GtkTreePath *
2947 _gtk_tree_view_find_path (GtkTreeView *tree_view,
2948                           GtkRBTree   *tree,
2949                           GtkRBNode   *node)
2950 {
2951   GtkTreePath *path;
2952   GtkRBTree *tmp_tree;
2953   GtkRBNode *tmp_node, *last;
2954   gint count;
2955
2956   path = gtk_tree_path_new ();
2957
2958   g_return_val_if_fail (node != NULL, path);
2959   g_return_val_if_fail (node != tree->nil, path);
2960
2961   count = 1 + node->left->count;
2962
2963   last = node;
2964   tmp_node = node->parent;
2965   tmp_tree = tree;
2966   while (tmp_tree)
2967     {
2968       while (tmp_node != tmp_tree->nil)
2969         {
2970           if (tmp_node->right == last)
2971             count += 1 + tmp_node->left->count;
2972           last = tmp_node;
2973           tmp_node = tmp_node->parent;
2974         }
2975       gtk_tree_path_prepend_index (path, count - 1);
2976       last = tmp_tree->parent_node;
2977       tmp_tree = tmp_tree->parent_tree;
2978       if (last)
2979         {
2980           count = 1 + last->left->count;
2981           tmp_node = last->parent;
2982         }
2983     }
2984   return path;
2985 }
2986
2987 /* Returns whether or not it's a parent, or not */
2988 gboolean
2989 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
2990                           GtkTreePath  *path,
2991                           GtkRBTree   **tree,
2992                           GtkRBNode   **node)
2993 {
2994   GtkRBNode *tmpnode = NULL;
2995   GtkRBTree *tmptree = tree_view->priv->tree;
2996   gint *indices = gtk_tree_path_get_indices (path);
2997   gint depth = gtk_tree_path_get_depth (path);
2998   gint i = 0;
2999
3000   *node = NULL;
3001   *tree = NULL;
3002
3003   do
3004     {
3005       if (tmptree == NULL)
3006         {
3007           *node = tmpnode;
3008           *tree = tmptree;
3009           return TRUE;
3010         }
3011       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
3012       if (++i >= depth)
3013         {
3014           *node = tmpnode;
3015           *tree = tmptree;
3016           return FALSE;
3017         }
3018       tmptree = tmpnode->children;
3019     }
3020   while (1);
3021 }
3022
3023 static void
3024 gtk_tree_view_get_arrow_range (GtkTreeView *tree_view,
3025                                gint        *x1,
3026                                gint        *x2)
3027 {
3028   gint x_offset = 0;
3029   GList *list;
3030   GtkTreeViewColumn *tmp_column = NULL;
3031   gint total_width;
3032   gint i;
3033   
3034   i = 0;
3035   total_width = 0;
3036   for (list = tree_view->priv->columns; list; list = list->next)
3037     {
3038       tmp_column = list->data;
3039
3040       if (i == tree_view->priv->expander_column)
3041         {
3042           x_offset = total_width;
3043           break;
3044         }
3045           
3046       if (tmp_column->visible)
3047         total_width += tmp_column->width;
3048
3049       ++i;
3050     }
3051
3052   if (x1)
3053     *x1 = x_offset;
3054   
3055   if (tmp_column && tmp_column->visible)
3056     {
3057       /* +1 because x2 isn't included in the range. */
3058       if (x2)
3059         *x2 = x_offset + tree_view->priv->tab_offset + 1;
3060     }
3061   else
3062     {
3063       /* return an empty range, the expander column is hidden */
3064       if (x2)
3065         *x2 = x_offset;
3066     }
3067 }
3068
3069 static void
3070 gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
3071                                GtkRBTree    *tree,
3072                                GtkRBNode    *node,
3073                                GdkRectangle *clip_rect)
3074 {
3075   GdkRectangle rect;
3076
3077   rect.x = 0;
3078   rect.width = tree_view->priv->width;
3079   rect.y = _gtk_rbtree_node_find_offset (tree, node) +
3080     TREE_VIEW_VERTICAL_SEPARATOR/2 +
3081     TREE_VIEW_HEADER_HEIGHT (tree_view);
3082   rect.height = GTK_RBNODE_GET_HEIGHT (node) + TREE_VIEW_VERTICAL_SEPARATOR;
3083   if (clip_rect)
3084     {
3085       GdkRectangle new_rect;
3086        gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
3087        gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
3088                                    new_rect.x, new_rect.y,
3089                                    new_rect.width, new_rect.height);
3090     }
3091   else
3092     {
3093        gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
3094                                    rect.x, rect.y,
3095                                    rect.width, rect.height);
3096     }
3097 }
3098
3099 /* x and y are the mouse position
3100  */
3101 static void
3102 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
3103                           GtkRBTree   *tree,
3104                           GtkRBNode   *node,
3105                           gint         x,
3106                           gint         y)
3107 {
3108   GdkRectangle area;
3109   GtkStateType state;
3110   GtkWidget *widget;
3111   gint x_offset = 0;
3112   gint y_offset = 0;
3113   
3114   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
3115     return;
3116
3117   widget = GTK_WIDGET (tree_view);
3118
3119   y_offset = _gtk_rbtree_node_find_offset (tree, node) + TREE_VIEW_HEADER_HEIGHT (tree_view);
3120
3121   gtk_tree_view_get_arrow_range (tree_view, &x_offset, NULL);
3122   
3123   area.x = x_offset;
3124   area.y = y_offset + TREE_VIEW_VERTICAL_SEPARATOR;
3125   area.width = tree_view->priv->tab_offset - 2;
3126   area.height = GTK_RBNODE_GET_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPARATOR;
3127
3128   if (node == tree_view->priv->button_pressed_node)
3129     {
3130       if (x >= area.x && x <= (area.x + area.width) &&
3131           y >= area.y && y <= (area.y + area.height))
3132         state = GTK_STATE_ACTIVE;
3133       else
3134         state = GTK_STATE_NORMAL;
3135     }
3136   else
3137     {
3138       state = (node==tree_view->priv->prelight_node&&GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)?GTK_STATE_PRELIGHT:GTK_STATE_NORMAL);
3139     }
3140
3141   /* FIXME expander size should come from a style property */
3142 #define EXPANDER_SIZE 8
3143   gtk_paint_expander (widget->style,
3144                       tree_view->priv->bin_window,
3145                       state,
3146                       &area,
3147                       widget,
3148                       "treeview",
3149                       area.x,
3150                       (area.y + (area.height - EXPANDER_SIZE) / 2 - (area.height + 1) % 2),
3151                       node->children != NULL);
3152 #undef EXPANDER_SIZE
3153 }
3154
3155 void
3156 _gtk_tree_view_set_size (GtkTreeView     *tree_view,
3157                          gint             width,
3158                          gint             height)
3159 {
3160   GList *list;
3161   GtkTreeViewColumn *column;
3162   gint i;
3163
3164   if (width == tree_view->priv->width &&
3165       height == tree_view->priv->height)
3166     return;
3167   
3168   if (tree_view->priv->model == NULL)
3169     {
3170       tree_view->priv->width = width;
3171       tree_view->priv->height = height;
3172       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3173       return;
3174     }
3175   if (width == -1)
3176     {
3177       width = 0;
3178       for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
3179         {
3180           column = list->data;
3181           if (!column->visible)
3182             continue;
3183           width += TREE_VIEW_COLUMN_WIDTH (column);
3184         }
3185     }
3186   if (height == -1)
3187     height = tree_view->priv->tree->root->offset + TREE_VIEW_VERTICAL_SEPARATOR;
3188
3189   tree_view->priv->width = width;
3190   tree_view->priv->height = height;
3191
3192   if (tree_view->priv->hadjustment->upper != tree_view->priv->width)
3193     {
3194       tree_view->priv->hadjustment->upper = tree_view->priv->width;
3195       gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
3196     }
3197
3198   if (tree_view->priv->vadjustment->upper != tree_view->priv->height)
3199     {
3200       tree_view->priv->vadjustment->upper = tree_view->priv->height;
3201       gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
3202     }
3203
3204   if (GTK_WIDGET_REALIZED (tree_view))
3205     {
3206       gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
3207       gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
3208     }
3209   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3210 }
3211
3212 /* this function returns the new width of the column being resized given
3213  * the column and x position of the cursor; the x cursor position is passed
3214  * in as a pointer and automagicly corrected if it's beyond min/max limits
3215  */
3216 static gint
3217 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
3218                                 gint       i,
3219                                 gint      *x)
3220 {
3221   GtkTreeViewColumn *column;
3222   gint width;
3223
3224   /* first translate the x position from widget->window
3225    * to clist->clist_window
3226    */
3227
3228   column = g_list_nth (tree_view->priv->columns, i)->data;
3229   width = *x - column->button->allocation.x;
3230
3231   /* Clamp down the value */
3232   if (column->min_width == -1)
3233     width = MAX (column->button->requisition.width,
3234                  width);
3235   else
3236     width = MAX (column->min_width,
3237                  width);
3238   if (column->max_width != -1)
3239     width = MIN (width, column->max_width != -1);
3240   *x = column->button->allocation.x + width;
3241
3242   return width;
3243 }
3244
3245 /* Callbacks */
3246 static void
3247 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
3248                                   GtkTreeView     *tree_view)
3249 {
3250   if (GTK_WIDGET_REALIZED (tree_view))
3251     {
3252       gdk_window_move (tree_view->priv->bin_window,
3253                        - tree_view->priv->hadjustment->value,
3254                        - tree_view->priv->vadjustment->value);
3255       gdk_window_move (tree_view->priv->header_window,
3256                        - tree_view->priv->hadjustment->value,
3257                        0);
3258
3259       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
3260       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
3261     }
3262 }
3263
3264 \f
3265
3266 /* Public methods
3267  */
3268
3269 /**
3270  * gtk_tree_view_new:
3271  * 
3272  * Creates a new #GtkTreeView widget.
3273  * 
3274  * Return value: A newly created #GtkTreeView widget.
3275  **/
3276 GtkWidget *
3277 gtk_tree_view_new (void)
3278 {
3279   GtkTreeView *tree_view;
3280
3281   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
3282
3283   return GTK_WIDGET (tree_view);
3284 }
3285
3286 /**
3287  * gtk_tree_view_new_with_model:
3288  * @model: the model.
3289  * 
3290  * Creates a new #GtkTreeView widget with the model initialized to @model.
3291  * 
3292  * Return value: A newly created #GtkTreeView widget.
3293  **/
3294 GtkWidget *
3295 gtk_tree_view_new_with_model (GtkTreeModel *model)
3296 {
3297   GtkTreeView *tree_view;
3298
3299   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
3300   gtk_tree_view_set_model (tree_view, model);
3301
3302   return GTK_WIDGET (tree_view);
3303 }
3304
3305 /**
3306  * gtk_tree_view_get_model:
3307  * @tree_view: a #GtkTreeView
3308  * 
3309  * Returns the model the the #GtkTreeView is based on.  Returns NULL if the
3310  * model is unset.
3311  * 
3312  * Return value: A #GtkTreeModel, or NULL if none is currently being used.
3313  **/
3314 GtkTreeModel *
3315 gtk_tree_view_get_model (GtkTreeView *tree_view)
3316 {
3317   g_return_val_if_fail (tree_view != NULL, NULL);
3318   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3319
3320   return tree_view->priv->model;
3321 }
3322
3323 static void
3324 gtk_tree_view_setup_model (GtkTreeView *tree_view)
3325 {
3326   GtkTreePath *path;
3327   GtkTreeIter iter;
3328
3329   tree_view->priv->tree = _gtk_rbtree_new ();
3330
3331   gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
3332                       "changed",
3333                       gtk_tree_view_changed,
3334                       tree_view);
3335   gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
3336                       "inserted",
3337                       gtk_tree_view_inserted,
3338                       tree_view);
3339   gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
3340                       "child_toggled",
3341                       gtk_tree_view_child_toggled,
3342                       tree_view);
3343   gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
3344                       "deleted",
3345                       gtk_tree_view_deleted,
3346                       tree_view);
3347
3348   if (tree_view->priv->columns == NULL)
3349     return;
3350
3351   path = gtk_tree_path_new_root ();
3352
3353   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
3354     {
3355       gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
3356     }
3357   
3358   gtk_tree_path_free (path);
3359
3360   gtk_tree_view_create_buttons (tree_view);
3361
3362   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3363 }
3364
3365 /**
3366  * gtk_tree_view_set_model:
3367  * @tree_view: A #GtkTreeNode.
3368  * @model: The model.
3369  * 
3370  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
3371  * set, it will remove it before setting the new model.  If @model is NULL, then
3372  * it will unset the old model.
3373  **/
3374 void
3375 gtk_tree_view_set_model (GtkTreeView  *tree_view,
3376                          GtkTreeModel *model)
3377 {
3378   g_return_if_fail (tree_view != NULL);
3379   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3380
3381   if (tree_view->priv->model != NULL)
3382     {
3383
3384       /* No longer do this. */
3385 #if 0
3386       for (list = tree_view->priv->columns; list; list = list->next)
3387         {
3388           column = list->data;
3389           if (column->button)
3390             {
3391               gtk_widget_unparent (column->button);
3392               gdk_window_set_user_data (column->window, NULL);
3393               gdk_window_destroy (column->window);
3394             }
3395         }
3396 #endif
3397       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
3398         {
3399           gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
3400                                          gtk_tree_view_changed,
3401                                          tree_view);
3402           gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
3403                                          gtk_tree_view_inserted,
3404                                          tree_view);
3405           gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
3406                                          gtk_tree_view_child_toggled,
3407                                          tree_view);
3408           gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
3409                                          gtk_tree_view_deleted,
3410                                          tree_view);
3411           _gtk_rbtree_free (tree_view->priv->tree);
3412         }
3413 #if 0
3414       g_list_free (tree_view->priv->columns);
3415       tree_view->priv->columns = NULL;
3416 #endif
3417
3418       if (tree_view->priv->drag_dest_row)
3419         gtk_tree_path_free (tree_view->priv->drag_dest_row);
3420       
3421       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3422     }
3423
3424   tree_view->priv->model = model;
3425   if (model == NULL)
3426     {
3427       tree_view->priv->tree = NULL;
3428       if (GTK_WIDGET_REALIZED (tree_view))
3429         _gtk_tree_view_set_size (tree_view, 0, 0);
3430       return;
3431     }
3432   else if (GTK_WIDGET_REALIZED (tree_view))
3433     {
3434       gtk_tree_view_setup_model (tree_view);
3435       _gtk_tree_view_set_size (tree_view, -1, -1);
3436     }
3437 }
3438
3439 /**
3440  * gtk_tree_view_get_selection:
3441  * @tree_view: A #GtkTreeView.
3442  * 
3443  * Gets the #GtkTreeSelection associated with @tree_view.
3444  * 
3445  * Return value: A #GtkTreeSelection object.
3446  **/
3447 GtkTreeSelection *
3448 gtk_tree_view_get_selection (GtkTreeView *tree_view)
3449 {
3450   g_return_val_if_fail (tree_view != NULL, NULL);
3451   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3452
3453   if (tree_view->priv->selection == NULL)
3454     tree_view->priv->selection =
3455       _gtk_tree_selection_new_with_tree_view (tree_view);
3456
3457   return tree_view->priv->selection;
3458 }
3459
3460 /**
3461  * gtk_tree_view_get_hadjustment:
3462  * @tree_view: A #GtkTreeView
3463  * 
3464  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
3465  * 
3466  * Return value: A #GtkAdjustment object, or NULL if none is currently being
3467  * used.
3468  **/
3469 GtkAdjustment *
3470 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
3471 {
3472   g_return_val_if_fail (tree_view != NULL, NULL);
3473   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3474
3475   if (tree_view->priv->hadjustment == NULL)
3476     gtk_tree_view_set_hadjustment (tree_view, NULL);
3477   
3478   return tree_view->priv->hadjustment;
3479 }
3480
3481 /**
3482  * gtk_tree_view_set_hadjustment:
3483  * @tree_view: A #GtkTreeView
3484  * @adjustment: The #GtkAdjustment to set, or NULL
3485  * 
3486  * Sets the #GtkAdjustment for the current horizontal aspect.
3487  **/
3488 void
3489 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
3490                                GtkAdjustment *adjustment)
3491 {
3492   g_return_if_fail (tree_view != NULL);
3493   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3494
3495   gtk_tree_view_set_adjustments (tree_view,
3496                                  adjustment,
3497                                  tree_view->priv->vadjustment);
3498 }
3499
3500 /**
3501  * gtk_tree_view_get_vadjustment:
3502  * @tree_view: A #GtkTreeView
3503  * 
3504  * Gets the #GtkAdjustment currently being used for the vertical aspect.
3505  * 
3506  * Return value: A #GtkAdjustment object, or NULL if none is currently being
3507  * used.
3508  **/
3509 GtkAdjustment *
3510 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
3511 {
3512   g_return_val_if_fail (tree_view != NULL, NULL);
3513   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3514
3515   if (tree_view->priv->vadjustment == NULL)
3516     gtk_tree_view_set_vadjustment (tree_view, NULL);
3517   
3518   return tree_view->priv->vadjustment;
3519 }
3520
3521 /**
3522  * gtk_tree_view_set_vadjustment:
3523  * @tree_view: A #GtkTreeView
3524  * @adjustment: The #GtkAdjustment to set, or NULL
3525  * 
3526  * Sets the #GtkAdjustment for the current vertical aspect.
3527  **/
3528 void
3529 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
3530                                GtkAdjustment *adjustment)
3531 {
3532   g_return_if_fail (tree_view != NULL);
3533   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3534
3535   gtk_tree_view_set_adjustments (tree_view,
3536                                  tree_view->priv->hadjustment,
3537                                  adjustment);
3538 }
3539
3540 /**
3541  * gtk_tree_view_set_adjustments:
3542  * @tree_view: A #GtkTreeView
3543  * @hadj: The horizontal #GtkAdjustment to set, or NULL
3544  * @vadj: The vertical #GtkAdjustment to set, or NULL
3545  * 
3546  * Sets the horizonal and or vertical #GtkAdjustment.
3547  **/
3548 static void
3549 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
3550                                GtkAdjustment *hadj,
3551                                GtkAdjustment *vadj)
3552 {
3553   gboolean need_adjust = FALSE;
3554
3555   g_return_if_fail (tree_view != NULL);
3556   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3557
3558   if (hadj)
3559     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
3560   else
3561     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3562   if (vadj)
3563     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
3564   else
3565     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3566
3567   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
3568     {
3569       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
3570       gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
3571     }
3572
3573   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
3574     {
3575       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
3576       gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
3577     }
3578
3579   if (tree_view->priv->hadjustment != hadj)
3580     {
3581       tree_view->priv->hadjustment = hadj;
3582       gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
3583       gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
3584
3585       gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
3586                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
3587                           tree_view);
3588       need_adjust = TRUE;
3589     }
3590
3591   if (tree_view->priv->vadjustment != vadj)
3592     {
3593       tree_view->priv->vadjustment = vadj;
3594       gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
3595       gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
3596
3597       gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
3598                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
3599                           tree_view);
3600       need_adjust = TRUE;
3601     }
3602
3603   if (need_adjust)
3604     gtk_tree_view_adjustment_changed (NULL, tree_view);
3605 }
3606
3607
3608 /* Column and header operations */
3609
3610 /**
3611  * gtk_tree_view_get_headers_visible:
3612  * @tree_view: A #GtkTreeView.
3613  * 
3614  * Returns TRUE if the headers on the @tree_view are visible.
3615  * 
3616  * Return value: Whether the headers are visible or not.
3617  **/
3618 gboolean
3619 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
3620 {
3621   g_return_val_if_fail (tree_view != NULL, FALSE);
3622   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
3623
3624   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
3625 }
3626
3627 /**
3628  * gtk_tree_view_set_headers_visible:
3629  * @tree_view: A #GtkTreeView.
3630  * @headers_visible: TRUE if the headers are visible
3631  * 
3632  * Sets the the visibility state of the headers.
3633  **/
3634 void
3635 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
3636                                    gboolean     headers_visible)
3637 {
3638   gint x, y;
3639   GList *list;
3640   GtkTreeViewColumn *column;
3641
3642   g_return_if_fail (tree_view != NULL);
3643   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3644
3645   headers_visible = !! headers_visible;
3646   
3647   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
3648     return;
3649
3650   if (headers_visible)
3651     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
3652   else
3653     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
3654
3655   if (GTK_WIDGET_REALIZED (tree_view))
3656     {
3657       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
3658       if (headers_visible)
3659         {
3660           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));
3661           
3662           if (GTK_WIDGET_MAPPED (tree_view))
3663             gtk_tree_view_map_buttons (tree_view);
3664         }
3665       else
3666         {
3667           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
3668
3669           for (list = tree_view->priv->columns; list; list = list->next)
3670             {
3671               column = list->data;
3672               gtk_widget_unmap (column->button);
3673             }
3674           gdk_window_hide (tree_view->priv->header_window);
3675         }
3676     }
3677
3678   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
3679   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
3680   tree_view->priv->vadjustment->lower = 0;
3681   tree_view->priv->vadjustment->upper = tree_view->priv->height;
3682   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
3683
3684   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3685 }
3686
3687
3688 /**
3689  * gtk_tree_view_columns_autosize:
3690  * @tree_view: A #GtkTreeView.
3691  * 
3692  * Resizes all columns to their optimal width.
3693  **/
3694 void
3695 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
3696 {
3697   gboolean dirty = FALSE;
3698   GList *list;
3699   GtkTreeViewColumn *column;
3700
3701   g_return_if_fail (tree_view != NULL);
3702   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3703
3704   for (list = tree_view->priv->columns; list; list = list->next)
3705     {
3706       column = list->data;
3707       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3708         continue;
3709       column->dirty = TRUE;
3710       dirty = TRUE;
3711     }
3712
3713   if (dirty)
3714     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3715 }
3716
3717 /**
3718  * gtk_tree_view_set_headers_clickable:
3719  * @tree_view: A #GtkTreeView.
3720  * @setting: TRUE if the columns are clickable.
3721  * 
3722  * Allow the column title buttons to be clicked.
3723  **/
3724 void
3725 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
3726                                      gboolean   setting)
3727 {
3728   GList *list;
3729
3730   g_return_if_fail (tree_view != NULL);
3731   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3732   g_return_if_fail (tree_view->priv->model != NULL);
3733
3734   for (list = tree_view->priv->columns; list; list = list->next)
3735     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
3736 }
3737
3738 /**
3739  * gtk_tree_view_append_column:
3740  * @tree_view: A #GtkTreeView.
3741  * @column: The #GtkTreeViewColumn to add.
3742  * 
3743  * Appends @column to the list of columns.
3744  * 
3745  * Return value: The number of columns in @tree_view after appending.
3746  **/
3747 gint
3748 gtk_tree_view_append_column (GtkTreeView       *tree_view,
3749                              GtkTreeViewColumn *column)
3750 {
3751   g_return_val_if_fail (tree_view != NULL, -1);
3752   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3753   g_return_val_if_fail (column != NULL, -1);
3754   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
3755   g_return_val_if_fail (column->tree_view == NULL, -1);
3756
3757   g_object_ref (G_OBJECT (column));
3758   gtk_object_sink (GTK_OBJECT (column));
3759   tree_view->priv->columns = g_list_append (tree_view->priv->columns, column);
3760   column->tree_view = GTK_WIDGET (tree_view);
3761
3762   tree_view->priv->n_columns++;
3763
3764   /* FIXME create header for the new column! */
3765   
3766   return tree_view->priv->n_columns;
3767 }
3768
3769
3770 /**
3771  * gtk_tree_view_remove_column:
3772  * @tree_view: A #GtkTreeView.
3773  * @column: The #GtkTreeViewColumn to remove.
3774  * 
3775  * Removes @column from @tree_view.
3776  * 
3777  * Return value: The number of columns in @tree_view after removing.
3778  **/
3779 gint
3780 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
3781                              GtkTreeViewColumn *column)
3782 {
3783   g_return_val_if_fail (tree_view != NULL, -1);
3784   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3785   g_return_val_if_fail (column != NULL, -1);
3786   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
3787   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
3788
3789   tree_view->priv->columns = g_list_remove (tree_view->priv->columns,
3790                                            column);
3791   column->tree_view = NULL;
3792   g_object_unref (G_OBJECT (column));
3793
3794   tree_view->priv->n_columns--;
3795
3796   /* FIXME destroy header for the column! */
3797   
3798   return tree_view->priv->n_columns;
3799 }
3800
3801 /**
3802  * gtk_tree_view_insert_column:
3803  * @tree_view: A #GtkTreeView.
3804  * @column: The #GtkTreeViewColumn to be inserted.
3805  * @position: The position to insert @column in.
3806  * 
3807  * This inserts the @column into the @tree_view at @position.
3808  * 
3809  * Return value: The number of columns in @tree_view after insertion.
3810  **/
3811 gint
3812 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
3813                              GtkTreeViewColumn *column,
3814                              gint               position)
3815 {
3816   g_return_val_if_fail (tree_view != NULL, -1);
3817   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3818   g_return_val_if_fail (column != NULL, -1);
3819   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
3820   g_return_val_if_fail (column->tree_view == NULL, -1);
3821
3822   g_object_ref (G_OBJECT (column));
3823   gtk_object_sink (GTK_OBJECT (column));
3824   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
3825                                            column, position);
3826   column->tree_view = GTK_WIDGET (tree_view);
3827
3828   tree_view->priv->n_columns++;
3829
3830   /* FIXME create header for the column! */
3831   
3832   return tree_view->priv->n_columns;
3833 }
3834
3835 /**
3836  * gtk_tree_view_get_column:
3837  * @tree_view: A #GtkTreeView.
3838  * @n: The position of the column, counting from 0.
3839  * 
3840  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
3841  * 
3842  * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
3843  * range of columns.
3844  **/
3845 GtkTreeViewColumn *
3846 gtk_tree_view_get_column (GtkTreeView *tree_view,
3847                           gint         n)
3848 {
3849   g_return_val_if_fail (tree_view != NULL, NULL);
3850   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3851   g_return_val_if_fail (tree_view->priv->model != NULL, NULL);
3852
3853   if (n < 0 || n >= tree_view->priv->n_columns)
3854     return NULL;
3855   
3856   if (tree_view->priv->columns == NULL)
3857     return NULL;
3858
3859   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
3860 }
3861
3862 void
3863 gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
3864                                    gint         col)
3865 {
3866   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3867
3868   if (tree_view->priv->expander_column != col)
3869     {
3870       tree_view->priv->expander_column = col;
3871
3872       /*   g_object_notify (G_OBJECT (tree_view), "expander_column"); */
3873     }
3874 }
3875
3876 gint
3877 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
3878 {
3879   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3880
3881   return tree_view->priv->expander_column;
3882 }
3883
3884 /**
3885  * gtk_tree_view_scroll_to_point:
3886  * @tree_view: a #GtkTreeView
3887  * @tree_x: X coordinate of new top-left pixel of visible area
3888  * @tree_y: Y coordinate of new top-left pixel of visible area
3889  * 
3890  * Scrolls the tree view such that the top-left corner of the visible
3891  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
3892  * in tree window coordinates.  The @tree_view must be realized before
3893  * this function is called.  If it isn't, you probably want ot be
3894  * using gtk_tree_view_scroll_to_cell.
3895  **/
3896 void
3897 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
3898                                gint         tree_x,
3899                                gint         tree_y)
3900 {
3901   GtkAdjustment *hadj;
3902   GtkAdjustment *vadj;
3903
3904   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3905   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
3906
3907   hadj = tree_view->priv->hadjustment;
3908   vadj = tree_view->priv->vadjustment;
3909
3910   gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
3911   gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));  
3912 }
3913
3914 /**
3915  * gtk_tree_view_scroll_to_cell
3916  * @tree_view: A #GtkTreeView.
3917  * @path: The path of the row to move to.
3918  * @column: The #GtkTreeViewColumn to move horizontally to.
3919  * @row_align: The vertical alignment of the row specified by @path.
3920  * @col_align: The horizontal alignment of the column specified by @column.
3921  * 
3922  * Moves the alignments of @tree_view to the position specified by
3923  * @column and @path.  If @column is NULL, then no horizontal
3924  * scrolling occurs.  Likewise, if @path is NULL no vertical scrolling
3925  * occurs.  @row_align determines where the row is placed, and
3926  * @col_align determines where @column is placed.  Both are expected
3927  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
3928  * right/bottom alignment, 0.5 means center.
3929  **/
3930 void
3931 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
3932                               GtkTreePath       *path,
3933                               GtkTreeViewColumn *column,
3934                               gfloat             row_align,
3935                               gfloat             col_align)
3936 {
3937   GdkRectangle cell_rect;
3938   GdkRectangle vis_rect;
3939   gint dest_x, dest_y;
3940   
3941   /* FIXME work on unmapped/unrealized trees? maybe implement when
3942    * we do incremental reflow for trees
3943    */
3944   
3945   g_return_if_fail (tree_view != NULL);
3946   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3947   g_return_if_fail (row_align >= 0.0);
3948   g_return_if_fail (row_align <= 1.0);
3949   g_return_if_fail (col_align >= 0.0);
3950   g_return_if_fail (col_align <= 1.0);
3951   g_return_if_fail (path != NULL || column != NULL);
3952
3953   row_align = CLAMP (row_align, 0.0, 1.0);
3954   col_align = CLAMP (col_align, 0.0, 1.0);
3955
3956   if (! GTK_WIDGET_REALIZED (tree_view))
3957     {
3958       if (path)
3959         tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
3960       if (column)
3961         tree_view->priv->scroll_to_column = column;
3962       tree_view->priv->scroll_to_row_align = row_align;
3963       tree_view->priv->scroll_to_col_align = col_align;
3964
3965       return;
3966     }
3967
3968   gtk_tree_view_get_cell_rect (tree_view, path, column, &cell_rect);
3969   gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
3970
3971   dest_x = vis_rect.x;
3972   dest_y = vis_rect.y;
3973   
3974   if (path)
3975     {
3976       dest_x = cell_rect.x +
3977         cell_rect.width * row_align -
3978         vis_rect.width * row_align;
3979     }
3980
3981   if (column)
3982     {
3983       dest_y = cell_rect.y +
3984         cell_rect.height * col_align -
3985         vis_rect.height * col_align;
3986     }
3987
3988   gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
3989 }
3990
3991 /**
3992  * gtk_tree_view_get_path_at_pos:
3993  * @tree_view: A #GtkTreeView.
3994  * @window: The #GdkWindow to check against.
3995  * @x: The x position to be identified.
3996  * @y: The y position to be identified.
3997  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
3998  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
3999  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
4000  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
4001  * 
4002  * Finds the path at the point (@x, @y) relative to @window.  If @window is
4003  * NULL, then the point is found relative to the widget coordinates.  This
4004  * function is expected to be called after an event, with event->window being
4005  * passed in as @window.  It is primarily for things like popup menus.  If @path
4006  * is non-NULL, then it will be filled with the #GtkTreePath at that point.
4007  * This path should be freed with #gtk_tree_path_free.  If @column is non-NULL,
4008  * then it will be filled with the column at that point. @cell_x and @cell_y return
4009  * the coordinates relative to the cell.
4010  * 
4011  * Return value: TRUE if a row exists at that coordinate.
4012  **/
4013 gboolean
4014 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
4015                                GdkWindow          *window,
4016                                gint                x,
4017                                gint                y,
4018                                GtkTreePath       **path,
4019                                GtkTreeViewColumn **column,
4020                                gint               *cell_x,
4021                                gint               *cell_y)
4022 {
4023   GtkRBTree *tree;
4024   GtkRBNode *node;
4025   gint y_offset;
4026   
4027   g_return_val_if_fail (tree_view != NULL, FALSE);
4028   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
4029   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
4030
4031   if (window)
4032     g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
4033
4034   if (path)
4035     *path = NULL;
4036   if (column)
4037     *column = NULL;
4038
4039   if (x > tree_view->priv->hadjustment->upper)
4040     return FALSE;
4041
4042   if (x < 0 || y < 0)
4043     return FALSE;
4044   
4045   if (column || cell_x)
4046     {
4047       GtkTreeViewColumn *tmp_column;
4048       GtkTreeViewColumn *last_column = NULL;
4049       GList *list;
4050       gint remaining_x = x;
4051       gboolean found = FALSE;
4052       
4053       for (list = tree_view->priv->columns; list; list = list->next)
4054         {
4055           tmp_column = list->data;
4056
4057           if (tmp_column->visible == FALSE)
4058             continue;
4059
4060           last_column = tmp_column;
4061           if (remaining_x <= tmp_column->width)
4062             {
4063               found = TRUE;
4064               
4065               if (column)
4066                 *column = tmp_column;
4067
4068               if (cell_x)
4069                 *cell_x = remaining_x;
4070               
4071               break;
4072             }
4073           remaining_x -= tmp_column->width;
4074         }
4075
4076       if (!found)
4077         {
4078           if (column)
4079             *column = last_column;
4080
4081           if (cell_x)
4082             *cell_x = last_column->width + remaining_x;
4083         }
4084     }
4085
4086   if (window)
4087     {
4088       y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
4089                                           y - TREE_VIEW_HEADER_HEIGHT (tree_view),
4090                                           &tree, &node);
4091     }
4092   else
4093     {
4094       if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
4095         return FALSE;
4096
4097       y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree, y - TREE_VIEW_HEADER_HEIGHT (tree_view) +
4098                                           tree_view->priv->vadjustment->value,
4099                                           &tree, &node);
4100     }
4101   
4102   if (tree == NULL)
4103     return FALSE;
4104
4105   if (cell_y)
4106     *cell_y = y_offset;
4107   
4108   if (path)
4109     *path = _gtk_tree_view_find_path (tree_view, tree, node);
4110
4111   return TRUE;
4112 }
4113
4114 /**
4115  * gtk_tree_view_get_cell_rect:
4116  * @tree_view: a #GtkTreeView
4117  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
4118  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
4119  * @rect: rectangle to fill with cell rect
4120  * 
4121  * Fills the bounding rectangle in tree window coordinates for the cell
4122  * at the row specified by @path and the column specified by @column.
4123  * If @path is %NULL, the y and height fields of the rectangle will be filled
4124  * with 0. If @column is %NULL, the x and width fields will be filled with 0.
4125  * 
4126  **/
4127 void
4128 gtk_tree_view_get_cell_rect (GtkTreeView        *tree_view,
4129                              GtkTreePath        *path,
4130                              GtkTreeViewColumn  *column,
4131                              GdkRectangle       *rect)
4132 {
4133   GtkTreeViewColumn *tmp_column = NULL;
4134   gint total_width;
4135   GList *list;
4136   GtkRBTree *tree = NULL;
4137   GtkRBNode *node = NULL;
4138   
4139   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4140   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
4141   g_return_if_fail (rect != NULL);
4142
4143   rect->x = 0;
4144   rect->y = 0;
4145   rect->width = 0;
4146   rect->height = 0;
4147   
4148   if (path)
4149     {
4150       /* Get vertical coords */
4151       
4152       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
4153       
4154       if (tree == NULL)
4155         {
4156           g_warning (G_STRLOC": no row corresponding to path");
4157           return;
4158         }
4159
4160       rect->y = _gtk_rbtree_node_find_offset (tree, node) + TREE_VIEW_HEADER_HEIGHT (tree_view);  
4161       
4162       rect->height = GTK_RBNODE_GET_HEIGHT (node);
4163     }
4164
4165   if (column && column->visible)
4166     {
4167       total_width = 0;
4168       for (list = tree_view->priv->columns; list; list = list->next)
4169         {
4170           tmp_column = list->data;
4171           
4172           if (tmp_column == column)
4173             {
4174               rect->x = total_width;
4175               break;
4176             }
4177           
4178           if (tmp_column->visible)
4179             total_width += tmp_column->width;
4180         }
4181       
4182       if (tmp_column != column)
4183         {
4184           g_warning (G_STRLOC": passed-in column isn't in the tree");
4185           return;
4186         }
4187   
4188       rect->width = column->width;
4189     }
4190 }
4191
4192 static void
4193 gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
4194                                  GtkRBNode  *node,
4195                                  gpointer  data)
4196 {
4197   GtkTreeView *tree_view = data;
4198
4199   if (node->children)
4200     _gtk_rbtree_traverse (node->children,
4201                           node->children->root,
4202                           G_PRE_ORDER,
4203                           gtk_tree_view_expand_all_helper,
4204                           data);
4205   else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
4206     {
4207       GtkTreePath *path;
4208       GtkTreeIter iter;
4209       GtkTreeIter child;
4210
4211       node->children = _gtk_rbtree_new ();
4212       node->children->parent_tree = tree;
4213       node->children->parent_node = node;
4214       path = _gtk_tree_view_find_path (tree_view, tree, node);
4215       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
4216       gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
4217       gtk_tree_view_build_tree (tree_view,
4218                                 node->children,
4219                                 &child,
4220                                 gtk_tree_path_get_depth (path) + 1,
4221                                 TRUE,
4222                                 GTK_WIDGET_REALIZED (tree_view));
4223       gtk_tree_path_free (path);
4224     }
4225 }
4226
4227 /**
4228  * gtk_tree_view_expand_all:
4229  * @tree_view: A #GtkTreeView.
4230  * 
4231  * Recursively expands all nodes in the @tree_view.
4232  **/
4233 void
4234 gtk_tree_view_expand_all (GtkTreeView *tree_view)
4235 {
4236   g_return_if_fail (tree_view != NULL);
4237   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4238   g_return_if_fail (tree_view->priv->tree != NULL);
4239
4240   _gtk_rbtree_traverse (tree_view->priv->tree,
4241                         tree_view->priv->tree->root,
4242                         G_PRE_ORDER,
4243                         gtk_tree_view_expand_all_helper,
4244                         tree_view);
4245
4246   _gtk_tree_view_set_size (tree_view, -1,-1);
4247 }
4248
4249 static void
4250 gtk_tree_view_collapse_all_helper (GtkRBTree  *tree,
4251                                    GtkRBNode  *node,
4252                                    gpointer    data)
4253 {
4254   if (node->children)
4255     {
4256       GtkTreePath *path;
4257       GtkTreeIter iter;
4258
4259       path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
4260                                        node->children,
4261                                        node->children->root);
4262       gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
4263                                &iter,
4264                                path);
4265       gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
4266                                     node->children,
4267                                     &iter,
4268                                     gtk_tree_path_get_depth (path));
4269       _gtk_rbtree_remove (node->children);
4270       gtk_tree_path_free (path);
4271     }
4272 }
4273
4274 /**
4275  * gtk_tree_view_collapse_all:
4276  * @tree_view: A #GtkTreeView.
4277  * 
4278  * Recursively collapses all visible, expanded nodes in @tree_view.
4279  **/
4280 void
4281 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
4282 {
4283   g_return_if_fail (tree_view != NULL);
4284   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4285   g_return_if_fail (tree_view->priv->tree != NULL);
4286
4287   _gtk_rbtree_traverse (tree_view->priv->tree,
4288                         tree_view->priv->tree->root,
4289                         G_PRE_ORDER,
4290                         gtk_tree_view_collapse_all_helper,
4291                         tree_view);
4292
4293   if (GTK_WIDGET_MAPPED (tree_view))
4294     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4295 }
4296
4297 /* FIXME the bool return values for expand_row and collapse_row are
4298  * not analagous; they should be TRUE if the row had children and
4299  * was not already in the requested state.
4300  */
4301
4302 /**
4303  * gtk_tree_view_expand_row:
4304  * @tree_view: a #GtkTreeView
4305  * @path: path to a row
4306  * @open_all: whether to recursively expand, or just expand immediate children
4307  * 
4308  * Opens the row so its children are visible
4309  * 
4310  * Return value: %TRUE if the row existed and had children
4311  **/
4312 gboolean
4313 gtk_tree_view_expand_row (GtkTreeView *tree_view,
4314                           GtkTreePath *path,
4315                           gboolean     open_all)
4316 {
4317   GtkTreeIter iter;
4318   GtkTreeIter child;
4319   GtkRBTree *tree;
4320   GtkRBNode *node;
4321
4322   g_return_val_if_fail (tree_view != NULL, FALSE);
4323   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
4324   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
4325   g_return_val_if_fail (path != NULL, FALSE);
4326
4327   if (_gtk_tree_view_find_node (tree_view,
4328                                 path,
4329                                 &tree,
4330                                 &node))
4331     return FALSE;
4332
4333   if (node->children)
4334     return TRUE;
4335   
4336   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
4337   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
4338     return FALSE;
4339   
4340   node->children = _gtk_rbtree_new ();
4341   node->children->parent_tree = tree;
4342   node->children->parent_node = node;
4343
4344   gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
4345   gtk_tree_view_build_tree (tree_view,
4346                             node->children,
4347                             &child,
4348                             gtk_tree_path_get_depth (path) + 1,
4349                             open_all,
4350                             GTK_WIDGET_REALIZED (tree_view));
4351
4352   if (GTK_WIDGET_MAPPED (tree_view))
4353     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4354
4355   return TRUE;
4356 }
4357
4358 /**
4359  * gtk_tree_view_collapse_row:
4360  * @tree_view: a #GtkTreeView
4361  * @path: path to a row in the @tree_view
4362  * 
4363  * Collapses a row (hides its child rows).
4364  * 
4365  * Return value: %TRUE if the row was expanded
4366  **/
4367 gboolean
4368 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
4369                             GtkTreePath *path)
4370 {
4371   GtkRBTree *tree;
4372   GtkRBNode *node;
4373   GtkTreeIter iter;
4374
4375   g_return_val_if_fail (tree_view != NULL, FALSE);
4376   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
4377   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
4378   g_return_val_if_fail (path != NULL, FALSE);
4379
4380   if (_gtk_tree_view_find_node (tree_view,
4381                                 path,
4382                                 &tree,
4383                                 &node))
4384     return FALSE;
4385
4386   if (node->children == NULL)
4387     return FALSE;
4388
4389   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
4390   gtk_tree_view_discover_dirty (tree_view,
4391                                 node->children,
4392                                 &iter,
4393                                 gtk_tree_path_get_depth (path));
4394   _gtk_rbtree_remove (node->children);
4395
4396   if (GTK_WIDGET_MAPPED (tree_view))
4397     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4398
4399   return TRUE;
4400 }
4401
4402 /**
4403  * gtk_tree_view_get_visible_rect:
4404  * @tree_view: a #GtkTreeView
4405  * @visible_rect: rectangle to fill
4406  *
4407  * Fills @visible_rect with the currently-visible region of the
4408  * buffer, in tree coordinates. Convert to widget coordinates with
4409  * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
4410  * 0,0 for row 0 of the tree, and cover the entire scrollable area of
4411  * the tree.
4412  **/
4413 void
4414 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
4415                                 GdkRectangle *visible_rect)
4416 {
4417   GtkWidget *widget;
4418
4419   g_return_if_fail (tree_view != NULL);
4420   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4421
4422   widget = GTK_WIDGET (tree_view);
4423
4424   if (visible_rect)
4425     {
4426       visible_rect->x = tree_view->priv->hadjustment->value;
4427       visible_rect->y = tree_view->priv->vadjustment->value;
4428       visible_rect->width = widget->allocation.width;
4429       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
4430     }
4431 }
4432
4433 /**
4434  * gtk_tree_view_widget_to_tree_coords:
4435  * @tree_view: a #GtkTreeView
4436  * @wx: widget X coordinate
4437  * @wy: widget Y coordinate
4438  * @tx: return location for tree X coordinate
4439  * @ty: return location for tree Y coordinate
4440  *
4441  * Converts widget coordinates to coordinates for the
4442  * tree window (the full scrollable area of the tree).
4443  * 
4444  **/
4445 void
4446 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
4447                                      gint         wx,
4448                                      gint         wy,
4449                                      gint        *tx,
4450                                      gint        *ty)
4451 {
4452   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4453   
4454   if (tx)
4455     {
4456       *tx = wx + tree_view->priv->hadjustment->value;
4457     }
4458
4459   if (ty)
4460     {
4461       *ty = wy - TREE_VIEW_HEADER_HEIGHT (tree_view) +
4462         tree_view->priv->vadjustment->value;
4463     }
4464 }
4465
4466 /**
4467  * gtk_tree_view_tree_to_widget_coords:
4468  * @tree_view: a #GtkTreeView
4469  * @tx: tree X coordinate
4470  * @ty: tree Y coordinate
4471  * @wx: return location for widget X coordinate
4472  * @wy: return location for widget Y coordinate
4473  *
4474  * Converts tree coordinates (coordinates in full scrollable
4475  * area of the tree) to widget coordinates.
4476  * 
4477  **/
4478 void
4479 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
4480                                      gint         tx,
4481                                      gint         ty,
4482                                      gint        *wx,
4483                                      gint        *wy)
4484 {
4485   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4486
4487   if (wx)
4488     {
4489       *wx = tx - tree_view->priv->hadjustment->value;
4490     }
4491
4492   if (wy)
4493     {
4494       *wy = ty + TREE_VIEW_HEADER_HEIGHT (tree_view) -
4495         tree_view->priv->vadjustment->value;
4496     }
4497 }
4498
4499 /* Drag-and-drop */
4500
4501 typedef struct _TreeViewDragInfo TreeViewDragInfo;
4502
4503 struct _TreeViewDragInfo
4504 {
4505   GdkModifierType start_button_mask;
4506   GtkTargetList *source_target_list;
4507   GdkDragAction source_actions;
4508   GClosure *row_draggable_closure;
4509   GtkTreePath *source_row;
4510
4511   GtkTargetList *dest_target_list;
4512   GClosure *location_droppable_closure;
4513   
4514   guint source_set : 1;
4515   guint dest_set : 1;
4516 };
4517
4518 static TreeViewDragInfo*
4519 get_info (GtkTreeView *tree_view)
4520 {
4521   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
4522 }
4523
4524 static void
4525 clear_source_info (TreeViewDragInfo *di)
4526 {
4527   if (di->source_target_list)
4528     gtk_target_list_unref (di->source_target_list);
4529
4530   if (di->row_draggable_closure)
4531     g_closure_unref (di->row_draggable_closure);
4532
4533   if (di->source_row)
4534     gtk_tree_path_free (di->source_row);
4535   
4536   di->source_target_list = NULL;
4537   di->row_draggable_closure = NULL;
4538   di->source_row = NULL;
4539 }
4540
4541 static void
4542 clear_dest_info (TreeViewDragInfo *di)
4543 {
4544   if (di->location_droppable_closure)
4545     g_closure_unref (di->location_droppable_closure);
4546
4547   if (di->dest_target_list)
4548     gtk_target_list_unref (di->dest_target_list);
4549   
4550   di->location_droppable_closure = NULL;
4551   di->dest_target_list = NULL;
4552 }
4553
4554 static void
4555 destroy_info (TreeViewDragInfo *di)
4556 {
4557   clear_source_info (di);
4558   clear_dest_info (di);
4559   g_free (di);
4560 }
4561
4562 static TreeViewDragInfo*
4563 ensure_info (GtkTreeView *tree_view)
4564 {
4565   TreeViewDragInfo *di;
4566
4567   di = get_info (tree_view);
4568
4569   if (di == NULL)
4570     {
4571       di = g_new0 (TreeViewDragInfo, 1);
4572       
4573       g_object_set_data_full (G_OBJECT (tree_view),
4574                               "gtk-tree-view-drag-info",
4575                               di,
4576                               (GDestroyNotify) destroy_info);
4577     }
4578
4579   return di;
4580 }
4581
4582 static void
4583 remove_info (GtkTreeView *tree_view)
4584 {
4585   g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
4586 }
4587
4588 #define SCROLL_EDGE_SIZE 15
4589
4590 static gint
4591 drag_scan_timeout (gpointer data)
4592 {
4593   GtkTreeView *tree_view;
4594   gint x, y;
4595   GdkModifierType state;
4596   GtkTreePath *path = NULL;
4597   GtkTreeViewColumn *column = NULL;
4598   GdkRectangle visible_rect;
4599   
4600   tree_view = GTK_TREE_VIEW (data);
4601
4602   gdk_window_get_pointer (tree_view->priv->bin_window,
4603                           &x, &y, &state);  
4604
4605   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4606
4607   /* See if we are near the edge. */
4608   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
4609       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
4610       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
4611       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
4612     {
4613       gtk_tree_view_get_path_at_pos (tree_view,
4614                                      tree_view->priv->bin_window,
4615                                      x, y,
4616                                      &path,
4617                                      &column,
4618                                      NULL,
4619                                      NULL);
4620       
4621       if (path != NULL)
4622         {
4623           gtk_tree_view_scroll_to_cell (tree_view,
4624                                         path,
4625                                         column,
4626                                         0.5, 0.5); 
4627           
4628           gtk_tree_path_free (path);
4629         }
4630     }
4631   
4632   return TRUE;
4633 }
4634
4635
4636 static void
4637 ensure_scroll_timeout (GtkTreeView *tree_view)
4638 {
4639   if (tree_view->priv->scroll_timeout == 0)
4640     tree_view->priv->scroll_timeout = gtk_timeout_add (50, drag_scan_timeout, tree_view);
4641 }
4642
4643 static void
4644 remove_scroll_timeout (GtkTreeView *tree_view)
4645 {
4646   if (tree_view->priv->scroll_timeout != 0)
4647     {
4648       gtk_timeout_remove (tree_view->priv->scroll_timeout);
4649       tree_view->priv->scroll_timeout = 0;
4650     }
4651 }
4652
4653 #ifdef __GNUC__
4654 #warning "implement g_closure_sink"
4655 #endif
4656 #define g_closure_sink(c)
4657
4658 void
4659 gtk_tree_view_set_rows_drag_source (GtkTreeView              *tree_view,
4660                                     GdkModifierType           start_button_mask,
4661                                     const GtkTargetEntry     *targets,
4662                                     gint                      n_targets,
4663                                     GdkDragAction             actions,
4664                                     GtkTreeViewDraggableFunc  row_draggable_func,
4665                                     gpointer                  user_data)
4666 {
4667   TreeViewDragInfo *di;
4668
4669   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4670   
4671   di = ensure_info (tree_view);
4672   clear_source_info (di);
4673
4674   di->start_button_mask = start_button_mask;
4675   di->source_target_list = gtk_target_list_new (targets, n_targets);
4676   di->source_actions = actions;
4677
4678   if (row_draggable_func)
4679     {
4680       di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
4681                                                   user_data, NULL);
4682       g_closure_ref (di->row_draggable_closure);
4683       g_closure_sink (di->row_draggable_closure);
4684     }
4685
4686   di->source_set = TRUE;
4687 }
4688
4689 void
4690 gtk_tree_view_set_rows_drag_dest (GtkTreeView              *tree_view,
4691                                   const GtkTargetEntry     *targets,
4692                                   gint                      n_targets,
4693                                   GdkDragAction             actions,
4694                                   GtkTreeViewDroppableFunc  location_droppable_func,
4695                                   gpointer                  user_data)
4696 {
4697   TreeViewDragInfo *di;
4698   
4699   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4700
4701   gtk_drag_dest_set (GTK_WIDGET (tree_view),
4702                      0,
4703                      NULL,
4704                      0,
4705                      actions);
4706   
4707   di = ensure_info (tree_view);
4708   clear_dest_info (di);  
4709
4710   if (targets)
4711     di->dest_target_list = gtk_target_list_new (targets, n_targets);
4712
4713   if (location_droppable_func)
4714     {
4715       di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
4716                                                        user_data, NULL);
4717       g_closure_ref (di->location_droppable_closure);
4718       g_closure_sink (di->location_droppable_closure);
4719     }
4720   
4721   di->dest_set = TRUE;
4722 }
4723
4724 void
4725 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
4726 {
4727   TreeViewDragInfo *di;
4728   
4729   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4730   
4731   di = get_info (tree_view);
4732
4733   if (di)
4734     {
4735       if (di->source_set)
4736         {
4737           clear_source_info (di);
4738           di->source_set = FALSE;
4739         }
4740
4741       if (!di->dest_set && !di->source_set)
4742         remove_info (tree_view);
4743     }
4744 }
4745
4746 void
4747 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
4748 {
4749   TreeViewDragInfo *di;
4750   
4751   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4752   
4753   di = get_info (tree_view);
4754
4755   if (di)
4756     {
4757       if (di->dest_set)
4758         {
4759           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
4760           clear_dest_info (di);
4761           di->dest_set = FALSE;
4762         }
4763
4764       if (!di->dest_set && !di->source_set)
4765         remove_info (tree_view);
4766     }
4767 }
4768
4769
4770 void
4771 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
4772                                  GtkTreePath            *path,
4773                                  GtkTreeViewDropPosition pos)
4774 {
4775   /* Note; this function is exported to allow a custom DND
4776    * implementation, so it can't touch TreeViewDragInfo
4777    */
4778   
4779   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4780
4781   if (tree_view->priv->drag_dest_row)
4782     {
4783       /* FIXME queue undraw on previous location */
4784       gtk_tree_path_free (tree_view->priv->drag_dest_row);
4785     }
4786
4787   tree_view->priv->drag_dest_pos = pos;
4788   
4789   if (path)
4790     tree_view->priv->drag_dest_row = gtk_tree_path_copy (path);
4791   else
4792     tree_view->priv->drag_dest_row = NULL;
4793
4794   /* FIXME this is crap, queue draw only on the newly-highlighted row */
4795   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4796 }
4797
4798 gboolean
4799 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
4800                                    gint                     drag_x,
4801                                    gint                     drag_y,
4802                                    GtkTreePath            **path,
4803                                    GtkTreeViewDropPosition *pos)
4804 {
4805   gint cell_y;
4806   gdouble offset_into_row;
4807   gdouble quarter;
4808   gint x, y;
4809   GdkRectangle cell;
4810   GtkTreeViewColumn *column = NULL;
4811   GtkTreePath *tmp_path = NULL;
4812   
4813   /* Note; this function is exported to allow a custom DND
4814    * implementation, so it can't touch TreeViewDragInfo
4815    */
4816   
4817   g_return_val_if_fail (tree_view != NULL, FALSE);
4818   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
4819   g_return_val_if_fail (drag_x >= 0, FALSE);
4820   g_return_val_if_fail (drag_y >= 0, FALSE);
4821   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
4822
4823   if (path)
4824     *path = NULL;
4825
4826   /* remember that drag_x and drag_y are in widget coords, convert to rbtree */
4827
4828   gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
4829                                        &x, &y);
4830   
4831   /* If in the top quarter of a row, we drop before that row; if
4832    * in the bottom quarter, drop after that row; if in the middle,
4833    * and the row has children, drop into the row.
4834    */
4835
4836   if (!gtk_tree_view_get_path_at_pos (tree_view,
4837                                       tree_view->priv->bin_window,
4838                                       x, y,
4839                                       &tmp_path,
4840                                       &column,
4841                                       NULL,
4842                                       &cell_y))
4843     return FALSE;  
4844
4845   gtk_tree_view_get_cell_rect (tree_view, tmp_path, column,
4846                                &cell);
4847
4848   offset_into_row = cell_y;
4849   
4850   if (path)
4851     *path = tmp_path;
4852   else
4853     gtk_tree_path_free (tmp_path);
4854
4855   tmp_path = NULL;
4856   
4857   quarter = cell.height / 4.0;
4858   
4859   if (pos)
4860     {
4861       if (offset_into_row < quarter)
4862         {
4863           *pos = GTK_TREE_VIEW_DROP_BEFORE;          
4864         }
4865       else if (offset_into_row < quarter * 2)
4866         {
4867           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
4868         }
4869       else if (offset_into_row < quarter * 3)
4870         {
4871           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
4872         }
4873       else
4874         {
4875           *pos = GTK_TREE_VIEW_DROP_AFTER;
4876         }
4877     }
4878
4879   return TRUE;
4880 }
4881
4882 gboolean
4883 gtk_selection_data_set_tree_row (GtkSelectionData *selection_data,
4884                                  GtkTreeView      *tree_view,
4885                                  GtkTreePath      *path)
4886 {
4887
4888   return FALSE;
4889 }
4890
4891 gboolean
4892 gtk_selection_data_get_tree_row (GtkSelectionData *selection_data,
4893                                  GtkTreeView     **tree_view,
4894                                  GtkTreePath     **path)
4895 {
4896   return FALSE;
4897 }
4898
4899
4900 static gboolean
4901 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
4902                                         GdkEventMotion   *event)
4903 {
4904   GdkDragContext *context;
4905   TreeViewDragInfo *di;
4906   GtkTreePath *path = NULL;
4907   gint button;
4908   gint cell_x, cell_y;
4909   
4910   di = get_info (tree_view);
4911
4912   if (di == NULL)
4913     return FALSE;
4914
4915   if (tree_view->priv->pressed_button < 0)
4916     return FALSE;
4917
4918   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
4919                                  tree_view->priv->press_start_x,
4920                                  tree_view->priv->press_start_y,
4921                                  event->x, event->y))
4922     return FALSE;
4923   
4924   button = tree_view->priv->pressed_button;
4925   tree_view->priv->pressed_button = -1;
4926
4927   gtk_tree_view_get_path_at_pos (tree_view,
4928                                  tree_view->priv->bin_window,
4929                                  tree_view->priv->press_start_x,
4930                                  tree_view->priv->press_start_y,
4931                                  &path,
4932                                  NULL,
4933                                  &cell_x,
4934                                  &cell_y);
4935
4936   if (path == NULL)
4937     return FALSE;
4938   
4939   /* FIXME if the path doesn't match the row_draggable predicate,
4940    * return FALSE and free path
4941    */  
4942
4943   /* FIXME Check whether we're a start button, if not return FALSE and
4944    * free path
4945    */
4946   
4947   context = gtk_drag_begin (GTK_WIDGET (tree_view),
4948                             di->source_target_list,
4949                             di->source_actions,
4950                             button,
4951                             (GdkEvent*)event);
4952
4953   gtk_drag_set_icon_default (context);
4954
4955   {
4956     GdkPixmap *row_pix;
4957
4958     row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
4959                                                   path);
4960
4961     gtk_drag_set_icon_pixmap (context,
4962                               gdk_drawable_get_colormap (row_pix),
4963                               row_pix,
4964                               NULL,
4965                               /* the + 1 is for the black border in the icon */
4966                               tree_view->priv->press_start_x + 1,
4967                               cell_y + 1);
4968
4969     gdk_pixmap_unref (row_pix);
4970   }
4971   
4972   di->source_row = path;
4973   
4974   return TRUE;
4975 }
4976
4977 /* Default signal implementations for the drag signals */
4978
4979 static void
4980 gtk_tree_view_drag_begin (GtkWidget      *widget,
4981                           GdkDragContext *context)
4982 {
4983   /* do nothing */
4984 }
4985
4986 static void
4987 gtk_tree_view_drag_end (GtkWidget      *widget,
4988                         GdkDragContext *context)
4989 {
4990   /* do nothing */
4991 }
4992
4993 static void
4994 gtk_tree_view_drag_data_get (GtkWidget        *widget,
4995                              GdkDragContext   *context,
4996                              GtkSelectionData *selection_data,
4997                              guint             info,
4998                              guint             time)
4999 {
5000   GtkTreeView *tree_view;
5001
5002   tree_view = GTK_TREE_VIEW (widget);
5003
5004   if (selection_data->target == gdk_atom_intern ("GTK_TREE_VIEW_ROW", FALSE))
5005     {
5006       TreeViewDragInfo *di;
5007
5008       di = get_info (GTK_TREE_VIEW (widget));
5009
5010       if (di == NULL)
5011         {
5012           /* There's a race where someone could have unset
5013            * drag source before the data is requested
5014            */
5015           return;
5016         }
5017       
5018       gtk_selection_data_set_tree_row (selection_data,
5019                                        GTK_TREE_VIEW (widget),
5020                                        di->source_row);
5021     }
5022 }
5023
5024 static void
5025 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
5026                                 GdkDragContext *context)
5027 {
5028   /* FIXME we need to delete the source_row if we're doing automagical
5029    * reordering stuff.
5030    */
5031 }
5032
5033
5034 static void
5035 remove_open_timeout (GtkTreeView *tree_view)
5036 {
5037   if (tree_view->priv->open_dest_timeout != 0)
5038     {
5039       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
5040       tree_view->priv->open_dest_timeout = 0;
5041     }
5042 }
5043
5044 static void
5045 gtk_tree_view_drag_leave (GtkWidget      *widget,
5046                           GdkDragContext *context,
5047                           guint             time)
5048 {
5049   TreeViewDragInfo *di;
5050   
5051   di = get_info (GTK_TREE_VIEW (widget));
5052   
5053   /* unset any highlight row */
5054   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5055                                    NULL,
5056                                    GTK_TREE_VIEW_DROP_BEFORE);
5057   
5058   remove_scroll_timeout (GTK_TREE_VIEW (widget));
5059   remove_open_timeout (GTK_TREE_VIEW (widget));
5060 }
5061
5062 static gint
5063 open_row_timeout (gpointer data)
5064 {
5065   GtkTreeView *tree_view = data;
5066
5067   if (tree_view->priv->drag_dest_row &&
5068       (tree_view->priv->drag_dest_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
5069        tree_view->priv->drag_dest_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
5070     {
5071       gtk_tree_view_expand_row (tree_view,
5072                                 tree_view->priv->drag_dest_row,
5073                                 FALSE);
5074       tree_view->priv->open_dest_timeout = 0;
5075       return FALSE;
5076     }  
5077   else
5078     return TRUE;
5079 }
5080
5081 static gboolean
5082 gtk_tree_view_drag_motion (GtkWidget        *widget,
5083                            GdkDragContext   *context,
5084                            gint              x,
5085                            gint              y,
5086                            guint             time)
5087 {
5088   GtkTreePath *path = NULL;
5089   TreeViewDragInfo *di;
5090   GtkTreeViewDropPosition pos;
5091   GtkTreeView *tree_view;
5092
5093   tree_view = GTK_TREE_VIEW (widget);
5094   
5095   di = get_info (GTK_TREE_VIEW (widget));  
5096   
5097   if (di == NULL)
5098     {
5099       /* someone unset us as a drag dest, note that if
5100        * we return FALSE drag_leave isn't called
5101        */
5102
5103       gtk_tree_view_set_drag_dest_row (tree_view,
5104                                        NULL,
5105                                        GTK_TREE_VIEW_DROP_BEFORE);
5106
5107       remove_scroll_timeout (GTK_TREE_VIEW (widget));
5108       remove_open_timeout (GTK_TREE_VIEW (widget));
5109       
5110       return FALSE; /* no longer a drop site */
5111     }
5112
5113   ensure_scroll_timeout (tree_view);
5114   
5115   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
5116                                           x, y,
5117                                           &path,
5118                                           &pos))
5119     {
5120       /* can't drop here */
5121       remove_open_timeout (tree_view);
5122       
5123       gdk_drag_status (context, 0, time);
5124
5125       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5126                                        NULL,
5127                                        GTK_TREE_VIEW_DROP_BEFORE);
5128
5129       /* don't propagate to parent though */
5130       return TRUE;
5131     }
5132   
5133   g_assert (path);
5134
5135   /* If we left the current row's "open" zone, unset the timeout for
5136    * opening the row
5137    */
5138   if (tree_view->priv->drag_dest_row &&
5139       (gtk_tree_path_compare (path, tree_view->priv->drag_dest_row) != 0 ||
5140        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
5141          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
5142     remove_open_timeout (tree_view);
5143   
5144   if (TRUE /* FIXME if the location droppable predicate */ &&
5145       gtk_drag_dest_find_target (widget, context, di->dest_target_list) != GDK_NONE)
5146     {
5147       GtkWidget *source_widget;
5148       GdkDragAction suggested_action;
5149       
5150       suggested_action = context->suggested_action;
5151       
5152       source_widget = gtk_drag_get_source_widget (context);
5153       
5154       if (source_widget == widget)
5155         {
5156           /* Default to MOVE, unless the user has
5157            * pressed ctrl or alt to affect available actions
5158            */
5159           if ((context->actions & GDK_ACTION_MOVE) != 0)
5160             suggested_action = GDK_ACTION_MOVE;
5161         }
5162       
5163       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5164                                        path, pos);
5165
5166       if (tree_view->priv->open_dest_timeout == 0)
5167         {
5168           tree_view->priv->open_dest_timeout =
5169             gtk_timeout_add (250, open_row_timeout, tree_view);      
5170         }
5171       
5172       gdk_drag_status (context, suggested_action, time);
5173     }
5174   else
5175     {
5176       /* can't drop here */
5177       remove_open_timeout (tree_view);
5178       
5179       gdk_drag_status (context, 0, time);
5180
5181       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5182                                        NULL,
5183                                        GTK_TREE_VIEW_DROP_BEFORE);
5184     }
5185
5186   gtk_tree_path_free (path);
5187   
5188   return TRUE;
5189 }
5190
5191 static gboolean
5192 gtk_tree_view_drag_drop (GtkWidget        *widget,
5193                          GdkDragContext   *context,
5194                          gint              x,
5195                          gint              y,
5196                          guint             time)
5197 {
5198   GdkAtom target = GDK_NONE;
5199   TreeViewDragInfo *di;
5200   GtkTreeView *tree_view;
5201
5202   tree_view = GTK_TREE_VIEW (widget);
5203
5204   remove_scroll_timeout (GTK_TREE_VIEW (widget));
5205   remove_open_timeout (GTK_TREE_VIEW (widget));
5206   
5207   di = get_info (tree_view);
5208
5209   if (di && tree_view->priv->drag_dest_row && di->dest_target_list)
5210     target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
5211
5212   if (target != GDK_NONE)
5213     {
5214       gtk_drag_get_data (widget, context, target, time);
5215       return TRUE;
5216     }
5217   else
5218     return FALSE;
5219 }
5220
5221 static void
5222 gtk_tree_view_drag_data_received (GtkWidget        *widget,
5223                                   GdkDragContext   *context,
5224                                   gint              x,
5225                                   gint              y,
5226                                   GtkSelectionData *selection_data,
5227                                   guint             info,
5228                                   guint             time)
5229 {  
5230   if (selection_data->length >= 0)
5231     {
5232       /* FIXME respond to contents of selection_data */
5233
5234     }
5235
5236   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5237                                    NULL,
5238                                    GTK_TREE_VIEW_DROP_BEFORE);
5239   
5240   gtk_drag_finish (context, 
5241                    (selection_data->length >= 0),
5242                    (context->action == GDK_ACTION_MOVE),
5243                    time);  
5244 }
5245
5246