]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
gtk/gtkclist.c (adjust_adjustments) gtk/gtklayout.c
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "gtktreeview.h"
22 #include "gtkrbtree.h"
23 #include "gtktreednd.h"
24 #include "gtktreeprivate.h"
25 #include "gtkcellrenderer.h"
26 #include "gtksignal.h"
27 #include "gtkmain.h"
28 #include "gtkmarshalers.h"
29 #include "gtkbutton.h"
30 #include "gtkalignment.h"
31 #include "gtklabel.h"
32 #include "gtkhbox.h"
33 #include "gtkarrow.h"
34 #include "gtkintl.h"
35 #include "gtkbindings.h"
36 #include "gtkcontainer.h"
37 #include "gtkentry.h"
38 #include "gtktreemodelsort.h"
39
40 #include <string.h>
41 #include <gdk/gdkkeysyms.h>
42
43 #define GTK_TREE_VIEW_SEARCH_DIALOG_KEY "gtk-tree-view-search-dialog"
44 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
45 #define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 50
46 #define SCROLL_EDGE_SIZE 15
47 #define EXPANDER_EXTRA_PADDING 4
48
49 /* The "background" areas of all rows/cells add up to cover the entire tree.
50  * The background includes all inter-row and inter-cell spacing.
51  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
52  * i.e. just the cells, no spacing.
53  */
54
55 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
56 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
57
58 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
59 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
60
61 /* This is in Window coordinates */
62 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
63 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
64
65
66 typedef struct _GtkTreeViewChild GtkTreeViewChild;
67 struct _GtkTreeViewChild
68 {
69   GtkWidget *widget;
70   gint x;
71   gint y;
72   gint width;
73   gint height;
74 };
75
76
77 typedef struct _TreeViewDragInfo TreeViewDragInfo;
78 struct _TreeViewDragInfo
79 {
80   GdkModifierType start_button_mask;
81   GtkTargetList *source_target_list;
82   GdkDragAction source_actions;
83
84   GtkTargetList *dest_target_list;
85
86   guint source_set : 1;
87   guint dest_set : 1;
88 };
89
90
91 /* Signals */
92 enum
93 {
94   ROW_ACTIVATED,
95   TEST_EXPAND_ROW,
96   TEST_COLLAPSE_ROW,
97   ROW_EXPANDED,
98   ROW_COLLAPSED,
99   COLUMNS_CHANGED,
100   CURSOR_CHANGED,
101   MOVE_CURSOR,
102   SELECT_ALL,
103   SELECT_CURSOR_ROW,
104   TOGGLE_CURSOR_ROW,
105   EXPAND_COLLAPSE_CURSOR_ROW,
106   SELECT_CURSOR_PARENT,
107   START_INTERACTIVE_SEARCH,
108   LAST_SIGNAL
109 };
110
111 /* Properties */
112 enum {
113   PROP_0,
114   PROP_MODEL,
115   PROP_HADJUSTMENT,
116   PROP_VADJUSTMENT,
117   PROP_HEADERS_VISIBLE,
118   PROP_HEADERS_CLICKABLE,
119   PROP_EXPANDER_COLUMN,
120   PROP_REORDERABLE,
121   PROP_RULES_HINT,
122   PROP_ENABLE_SEARCH,
123   PROP_SEARCH_COLUMN,
124 };
125
126 static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
127 static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);
128
129 /* object signals */
130 static void     gtk_tree_view_finalize             (GObject          *object);
131 static void     gtk_tree_view_set_property         (GObject         *object,
132                                                     guint            prop_id,
133                                                     const GValue    *value,
134                                                     GParamSpec      *pspec);
135 static void     gtk_tree_view_get_property         (GObject         *object,
136                                                     guint            prop_id,
137                                                     GValue          *value,
138                                                     GParamSpec      *pspec);
139
140 /* gtkobject signals */
141 static void     gtk_tree_view_destroy              (GtkObject        *object);
142
143 /* gtkwidget signals */
144 static void     gtk_tree_view_realize              (GtkWidget        *widget);
145 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
146 static void     gtk_tree_view_map                  (GtkWidget        *widget);
147 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
148                                                     GtkRequisition   *requisition);
149 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
150                                                     GtkAllocation    *allocation);
151 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
152                                                     GdkEventExpose   *event);
153 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
154                                                     GdkEventKey      *event);
155 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
156                                                     GdkEventMotion   *event);
157 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
158                                                     GdkEventCrossing *event);
159 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
160                                                     GdkEventCrossing *event);
161 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
162                                                     GdkEventButton   *event);
163 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
164                                                     GdkEventButton   *event);
165 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
166                                                     GtkWidget        *child);
167 static gint     gtk_tree_view_focus_in             (GtkWidget        *widget,
168                                                     GdkEventFocus    *event);
169 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
170                                                     GdkEventFocus    *event);
171 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
172                                                     GtkDirectionType  direction);
173 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
174                                                     GtkStyle         *previous_style);
175
176 /* container signals */
177 static void     gtk_tree_view_remove               (GtkContainer     *container,
178                                                     GtkWidget        *widget);
179 static void     gtk_tree_view_forall               (GtkContainer     *container,
180                                                     gboolean          include_internals,
181                                                     GtkCallback       callback,
182                                                     gpointer          callback_data);
183
184 /* Source side drag signals */
185 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
186                                             GdkDragContext   *context);
187 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
188                                             GdkDragContext   *context);
189 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
190                                             GdkDragContext   *context,
191                                             GtkSelectionData *selection_data,
192                                             guint             info,
193                                             guint             time);
194 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
195                                             GdkDragContext   *context);
196
197 /* Target side drag signals */
198 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
199                                                   GdkDragContext   *context,
200                                                   guint             time);
201 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
202                                                   GdkDragContext   *context,
203                                                   gint              x,
204                                                   gint              y,
205                                                   guint             time);
206 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
207                                                   GdkDragContext   *context,
208                                                   gint              x,
209                                                   gint              y,
210                                                   guint             time);
211 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
212                                                   GdkDragContext   *context,
213                                                   gint              x,
214                                                   gint              y,
215                                                   GtkSelectionData *selection_data,
216                                                   guint             info,
217                                                   guint             time);
218
219 /* tree_model signals */
220 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
221                                                            GtkAdjustment   *hadj,
222                                                            GtkAdjustment   *vadj);
223 static void gtk_tree_view_real_move_cursor                (GtkTreeView     *tree_view,
224                                                            GtkMovementStep  step,
225                                                            gint             count);
226 static void gtk_tree_view_real_select_all                 (GtkTreeView     *tree_view);
227 static void gtk_tree_view_real_select_cursor_row          (GtkTreeView     *tree_view,
228                                                            gboolean         start_editing);
229 static void gtk_tree_view_real_toggle_cursor_row          (GtkTreeView     *tree_view);
230 static void gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
231                                                            gboolean         logical,
232                                                            gboolean         expand,
233                                                            gboolean         open_all);
234 static void gtk_tree_view_real_select_cursor_parent       (GtkTreeView     *tree_view);
235 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
236                                                            GtkTreePath     *path,
237                                                            GtkTreeIter     *iter,
238                                                            gpointer         data);
239 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
240                                                            GtkTreePath     *path,
241                                                            GtkTreeIter     *iter,
242                                                            gpointer         data);
243 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
244                                                            GtkTreePath     *path,
245                                                            GtkTreeIter     *iter,
246                                                            gpointer         data);
247 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
248                                                            GtkTreePath     *path,
249                                                            gpointer         data);
250 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
251                                                            GtkTreePath     *parent,
252                                                            GtkTreeIter     *iter,
253                                                            gint            *new_order,
254                                                            gpointer         data);
255
256 /* Incremental reflow */
257 static gboolean validate_row             (GtkTreeView *tree_view,
258                                           GtkRBTree   *tree,
259                                           GtkRBNode   *node,
260                                           GtkTreeIter *iter,
261                                           GtkTreePath *path);
262 static void     validate_visible_area    (GtkTreeView *tree_view);
263 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
264 static gboolean presize_handler_callback (gpointer     data);
265 static void     install_presize_handler  (GtkTreeView *tree_view);
266 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
267 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
268
269
270 /* Internal functions */
271 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView       *tree_view,
272                                                               GtkTreeViewColumn *column);
273 static void     gtk_tree_view_add_move_binding               (GtkBindingSet     *binding_set,
274                                                               guint              keyval,
275                                                               guint              modmask,
276                                                               GtkMovementStep    step,
277                                                               gint               count);
278 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView       *tree_view,
279                                                               GtkRBTree         *tree);
280 static void     gtk_tree_view_queue_draw_path                (GtkTreeView       *tree_view,
281                                                               GtkTreePath       *path,
282                                                               GdkRectangle      *clip_rect);
283 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView       *tree_view,
284                                                               GtkRBTree         *tree,
285                                                               GtkRBNode         *node,
286                                                               GdkRectangle      *clip_rect);
287 static void     gtk_tree_view_draw_arrow                     (GtkTreeView       *tree_view,
288                                                               GtkRBTree         *tree,
289                                                               GtkRBNode         *node,
290                                                               gint               x,
291                                                               gint               y);
292 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView       *tree_view,
293                                                               GtkRBTree         *tree,
294                                                               gint              *x1,
295                                                               gint              *x2);
296 static gint     gtk_tree_view_new_column_width               (GtkTreeView       *tree_view,
297                                                               gint               i,
298                                                               gint              *x);
299 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment     *adjustment,
300                                                               GtkTreeView       *tree_view);
301 static void     gtk_tree_view_build_tree                     (GtkTreeView       *tree_view,
302                                                               GtkRBTree         *tree,
303                                                               GtkTreeIter       *iter,
304                                                               gint               depth,
305                                                               gboolean           recurse);
306 static gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView       *tree_view,
307                                                               GtkTreeIter       *iter,
308                                                               gint               depth,
309                                                               gint              *height,
310                                                               GtkRBNode         *node);
311 static void     gtk_tree_view_discover_dirty                 (GtkTreeView       *tree_view,
312                                                               GtkRBTree         *tree,
313                                                               GtkTreeIter       *iter,
314                                                               gint               depth);
315 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView       *tree_view,
316                                                               GtkRBTree         *tree,
317                                                               GtkRBNode         *node);
318 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView       *tree_view,
319                                                               GtkTreeViewColumn *column);
320 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView       *tree_view,
321                                                               GdkEventMotion    *event);
322 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView       *tree_view);
323 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView       *tree_view,
324                                                               gint               count);
325 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView       *tree_view,
326                                                               gint               count);
327 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView       *tree_view,
328                                                               gint               count);
329 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView       *tree_view,
330                                                               gint               count);
331 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView       *tree_view,
332                                                               GtkTreePath       *path,
333                                                               GtkRBTree         *tree,
334                                                               GtkRBNode         *node,
335                                                               gboolean           animate);
336 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView       *tree_view,
337                                                               GtkTreePath       *path,
338                                                               GtkRBTree         *tree,
339                                                               GtkRBNode         *node,
340                                                               gboolean           open_all,
341                                                               gboolean           animate);
342 static void     gtk_tree_view_real_set_cursor                (GtkTreeView       *tree_view,
343                                                               GtkTreePath       *path,
344                                                               gboolean           clear_and_select);
345
346 /* interactive search */
347 static void     gtk_tree_view_search_dialog_destroy     (GtkWidget        *search_dialog,
348                                                          GtkTreeView      *tree_view);
349 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
350                                                          GtkWidget        *search_dialog);
351 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
352                                                          GdkEventAny      *event,
353                                                          GtkTreeView      *tree_view);
354 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
355                                                          GdkEventButton   *event,
356                                                          GtkTreeView      *tree_view);
357 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
358                                                          GdkEventKey      *event,
359                                                          GtkTreeView      *tree_view);
360 static void     gtk_tree_view_search_move               (GtkWidget        *window,
361                                                          GtkTreeView      *tree_view,
362                                                          gboolean          up);
363 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
364                                                          gint              column,
365                                                          const gchar      *key,
366                                                          GtkTreeIter      *iter,
367                                                          gpointer          search_data);
368 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
369                                                          GtkTreeSelection *selection,
370                                                          GtkTreeIter      *iter,
371                                                          const gchar      *text,
372                                                          gint             *count,
373                                                          gint              n);
374 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
375                                                          GtkTreeView      *tree_view);
376 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
377                                                          GtkWidget        *child_widget,
378                                                          gint              x,
379                                                          gint              y,
380                                                          gint              width,
381                                                          gint              height);
382 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
383                                                          GtkTreePath      *cursor_path);
384 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
385                                               GtkTreeViewColumn *column,
386                                               GtkTreePath       *path,
387                                               GtkCellEditable   *cell_editable,
388                                               GdkRectangle      *cell_area,
389                                               GdkEvent          *event,
390                                               guint              flags);
391 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
392                                                          gboolean     cancel_editing);
393 static void gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view);
394
395
396 static GtkContainerClass *parent_class = NULL;
397 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
398
399 \f
400
401 /* GType Methods
402  */
403
404 GtkType
405 gtk_tree_view_get_type (void)
406 {
407   static GtkType tree_view_type = 0;
408
409   if (!tree_view_type)
410     {
411       static const GTypeInfo tree_view_info =
412       {
413         sizeof (GtkTreeViewClass),
414         NULL,           /* base_init */
415         NULL,           /* base_finalize */
416         (GClassInitFunc) gtk_tree_view_class_init,
417         NULL,           /* class_finalize */
418         NULL,           /* class_data */
419         sizeof (GtkTreeView),
420         0,              /* n_preallocs */
421         (GInstanceInitFunc) gtk_tree_view_init
422       };
423
424       tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
425     }
426
427   return tree_view_type;
428 }
429
430 static void
431 gtk_tree_view_class_init (GtkTreeViewClass *class)
432 {
433   GObjectClass *o_class;
434   GtkObjectClass *object_class;
435   GtkWidgetClass *widget_class;
436   GtkContainerClass *container_class;
437   GtkBindingSet *binding_set;
438
439   parent_class = g_type_class_peek_parent (class);
440   binding_set = gtk_binding_set_by_class (class);
441
442   o_class = (GObjectClass *) class;
443   object_class = (GtkObjectClass *) class;
444   widget_class = (GtkWidgetClass *) class;
445   container_class = (GtkContainerClass *) class;
446
447   /* GObject signals */
448   o_class->set_property = gtk_tree_view_set_property;
449   o_class->get_property = gtk_tree_view_get_property;
450   o_class->finalize = gtk_tree_view_finalize;
451
452   /* GtkObject signals */
453   object_class->destroy = gtk_tree_view_destroy;
454
455   /* GtkWidget signals */
456   widget_class->map = gtk_tree_view_map;
457   widget_class->realize = gtk_tree_view_realize;
458   widget_class->unrealize = gtk_tree_view_unrealize;
459   widget_class->size_request = gtk_tree_view_size_request;
460   widget_class->size_allocate = gtk_tree_view_size_allocate;
461   widget_class->button_press_event = gtk_tree_view_button_press;
462   widget_class->button_release_event = gtk_tree_view_button_release;
463   widget_class->motion_notify_event = gtk_tree_view_motion;
464   widget_class->expose_event = gtk_tree_view_expose;
465   widget_class->key_press_event = gtk_tree_view_key_press;
466   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
467   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
468   widget_class->focus_in_event = gtk_tree_view_focus_in;
469   widget_class->focus_out_event = gtk_tree_view_focus_out;
470   widget_class->drag_begin = gtk_tree_view_drag_begin;
471   widget_class->drag_end = gtk_tree_view_drag_end;
472   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
473   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
474   widget_class->drag_leave = gtk_tree_view_drag_leave;
475   widget_class->drag_motion = gtk_tree_view_drag_motion;
476   widget_class->drag_drop = gtk_tree_view_drag_drop;
477   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
478   widget_class->focus = gtk_tree_view_focus;
479   widget_class->style_set = gtk_tree_view_style_set;
480
481   /* GtkContainer signals */
482   container_class->remove = gtk_tree_view_remove;
483   container_class->forall = gtk_tree_view_forall;
484   container_class->set_focus_child = gtk_tree_view_set_focus_child;
485
486   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
487   class->move_cursor = gtk_tree_view_real_move_cursor;
488   class->select_all = gtk_tree_view_real_select_all;
489   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
490   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
491   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
492   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
493   class->start_interactive_search = gtk_tree_view_real_start_interactive_search;
494
495   /* Properties */
496
497   g_object_class_install_property (o_class,
498                                    PROP_MODEL,
499                                    g_param_spec_object ("model",
500                                                         _("TreeView Model"),
501                                                         _("The model for the tree view"),
502                                                         GTK_TYPE_TREE_MODEL,
503                                                         G_PARAM_READWRITE));
504
505   g_object_class_install_property (o_class,
506                                    PROP_HADJUSTMENT,
507                                    g_param_spec_object ("hadjustment",
508                                                         _("Horizontal Adjustment"),
509                                                         _("Horizontal Adjustment for the widget"),
510                                                         GTK_TYPE_ADJUSTMENT,
511                                                         G_PARAM_READWRITE));
512
513   g_object_class_install_property (o_class,
514                                    PROP_VADJUSTMENT,
515                                    g_param_spec_object ("vadjustment",
516                                                         _("Vertical Adjustment"),
517                                                         _("Vertical Adjustment for the widget"),
518                                                         GTK_TYPE_ADJUSTMENT,
519                                                         G_PARAM_READWRITE));
520
521   g_object_class_install_property (o_class,
522                                    PROP_HEADERS_VISIBLE,
523                                    g_param_spec_boolean ("headers_visible",
524                                                          _("Visible"),
525                                                          _("Show the column header buttons"),
526                                                          FALSE,
527                                                          G_PARAM_READWRITE));
528
529   g_object_class_install_property (o_class,
530                                    PROP_HEADERS_CLICKABLE,
531                                    g_param_spec_boolean ("headers_clickable",
532                                                          _("Headers Clickable"),
533                                                          _("Column headers respond to click events"),
534                                                          FALSE,
535                                                          G_PARAM_WRITABLE));
536
537   g_object_class_install_property (o_class,
538                                    PROP_EXPANDER_COLUMN,
539                                    g_param_spec_object ("expander_column",
540                                                         _("Expander Column"),
541                                                         _("Set the column for the expander column"),
542                                                         GTK_TYPE_TREE_VIEW_COLUMN,
543                                                         G_PARAM_READWRITE));
544
545   g_object_class_install_property (o_class,
546                                    PROP_REORDERABLE,
547                                    g_param_spec_boolean ("reorderable",
548                                                          _("Reorderable"),
549                                                          _("View is reorderable"),
550                                                          FALSE,
551                                                          G_PARAM_READWRITE));
552
553   g_object_class_install_property (o_class,
554                                    PROP_RULES_HINT,
555                                    g_param_spec_boolean ("rules_hint",
556                                                          _("Rules Hint"),
557                                                          _("Set a hint to the theme engine to draw rows in alternating colors"),
558                                                          FALSE,
559                                                          G_PARAM_READWRITE));
560
561     g_object_class_install_property (o_class,
562                                      PROP_ENABLE_SEARCH,
563                                      g_param_spec_boolean ("enable_search",
564                                                            _("Enable Search"),
565                                                            _("View allows user to search through columns interactively"),
566                                                            TRUE,
567                                                            G_PARAM_READWRITE));
568
569     g_object_class_install_property (o_class,
570                                      PROP_SEARCH_COLUMN,
571                                      g_param_spec_int ("search_column",
572                                                        _("Search Column"),
573                                                        _("Model column to search through when searching through code"),
574                                                        -1,
575                                                        G_MAXINT,
576                                                        0,
577                                                        G_PARAM_READWRITE));
578
579   /* Style properties */
580 #define _TREE_VIEW_EXPANDER_SIZE 10
581 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
582 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
583     
584   gtk_widget_class_install_style_property (widget_class,
585                                            g_param_spec_int ("expander_size",
586                                                              _("Expander Size"),
587                                                              _("Size of the expander arrow."),
588                                                              0,
589                                                              G_MAXINT,
590                                                              _TREE_VIEW_EXPANDER_SIZE,
591                                                              G_PARAM_READABLE));
592
593   gtk_widget_class_install_style_property (widget_class,
594                                            g_param_spec_int ("vertical_separator",
595                                                              _("Vertical Separator Width"),
596                                                              _("Vertical space between cells.  Must be an even number."),
597                                                              0,
598                                                              G_MAXINT,
599                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
600                                                              G_PARAM_READABLE));
601
602   gtk_widget_class_install_style_property (widget_class,
603                                            g_param_spec_int ("horizontal_separator",
604                                                              _("Horizontal Separator Width"),
605                                                              _("Horizontal space between cells.  Must be an even number."),
606                                                              0,
607                                                              G_MAXINT,
608                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
609                                                              G_PARAM_READABLE));
610
611   gtk_widget_class_install_style_property (widget_class,
612                                            g_param_spec_boolean ("allow_rules",
613                                                                  _("Allow Rules"),
614                                                                  _("Allow drawing of alternating color rows."),
615                                                                  TRUE,
616                                                                  G_PARAM_READABLE));
617
618   gtk_widget_class_install_style_property (widget_class,
619                                            g_param_spec_boolean ("indent_expanders",
620                                                                  _("Indent Expanders"),
621                                                                  _("Make the expanders indented."),
622                                                                  TRUE,
623                                                                  G_PARAM_READABLE));
624   /* Signals */
625   widget_class->set_scroll_adjustments_signal =
626     gtk_signal_new ("set_scroll_adjustments",
627                     GTK_RUN_LAST,
628                     GTK_CLASS_TYPE (object_class),
629                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
630                     _gtk_marshal_VOID__OBJECT_OBJECT,
631                     GTK_TYPE_NONE, 2,
632                     GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
633
634   tree_view_signals[ROW_ACTIVATED] =
635     gtk_signal_new ("row_activated",
636                     GTK_RUN_LAST | GTK_RUN_ACTION,
637                     GTK_CLASS_TYPE (object_class),
638                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
639                     _gtk_marshal_VOID__BOXED_OBJECT,
640                     GTK_TYPE_NONE, 2,
641                     GTK_TYPE_TREE_PATH,
642                     GTK_TYPE_TREE_VIEW_COLUMN);
643
644   tree_view_signals[TEST_EXPAND_ROW] =
645     g_signal_new ("test_expand_row",
646                   G_TYPE_FROM_CLASS (object_class),
647                   G_SIGNAL_RUN_LAST,
648                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
649                   _gtk_boolean_handled_accumulator, NULL,
650                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
651                   G_TYPE_BOOLEAN, 2,
652                   GTK_TYPE_TREE_ITER,
653                   GTK_TYPE_TREE_PATH);
654
655   tree_view_signals[TEST_COLLAPSE_ROW] =
656     g_signal_new ("test_collapse_row",
657                   G_TYPE_FROM_CLASS (object_class),
658                   G_SIGNAL_RUN_LAST,
659                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
660                   _gtk_boolean_handled_accumulator, NULL,
661                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
662                   G_TYPE_BOOLEAN, 2,
663                   GTK_TYPE_TREE_ITER,
664                   GTK_TYPE_TREE_PATH);
665
666   tree_view_signals[ROW_EXPANDED] =
667     g_signal_new ("row_expanded",
668                   G_TYPE_FROM_CLASS (object_class),
669                   G_SIGNAL_RUN_LAST,
670                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
671                   NULL, NULL,
672                   _gtk_marshal_VOID__BOXED_BOXED,
673                   GTK_TYPE_NONE, 2,
674                   GTK_TYPE_TREE_ITER,
675                   GTK_TYPE_TREE_PATH);
676
677   tree_view_signals[ROW_COLLAPSED] =
678     g_signal_new ("row_collapsed",
679                   G_TYPE_FROM_CLASS (object_class),
680                   G_SIGNAL_RUN_LAST,
681                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
682                   NULL, NULL,
683                   _gtk_marshal_VOID__BOXED_BOXED,
684                   GTK_TYPE_NONE, 2,
685                   GTK_TYPE_TREE_ITER,
686                   GTK_TYPE_TREE_PATH);
687
688   tree_view_signals[COLUMNS_CHANGED] =
689     g_signal_new ("columns_changed",
690                   G_TYPE_FROM_CLASS (object_class),
691                   G_SIGNAL_RUN_LAST,
692                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
693                   NULL, NULL,
694                   _gtk_marshal_NONE__NONE,
695                   G_TYPE_NONE, 0);
696
697   tree_view_signals[CURSOR_CHANGED] =
698     g_signal_new ("cursor_changed",
699                   G_TYPE_FROM_CLASS (object_class),
700                   G_SIGNAL_RUN_LAST,
701                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
702                   NULL, NULL,
703                   _gtk_marshal_NONE__NONE,
704                   G_TYPE_NONE, 0);
705
706   tree_view_signals[MOVE_CURSOR] =
707     g_signal_new ("move_cursor",
708                   G_TYPE_FROM_CLASS (object_class),
709                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
710                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
711                   NULL, NULL,
712                   _gtk_marshal_VOID__ENUM_INT,
713                   GTK_TYPE_NONE, 2, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT);
714
715   tree_view_signals[SELECT_ALL] =
716     g_signal_new ("select_all",
717                   G_TYPE_FROM_CLASS (object_class),
718                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
719                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
720                   NULL, NULL,
721                   _gtk_marshal_NONE__NONE,
722                   GTK_TYPE_NONE, 0);
723
724   tree_view_signals[SELECT_CURSOR_ROW] =
725     g_signal_new ("select_cursor_row",
726                   G_TYPE_FROM_CLASS (object_class),
727                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
728                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
729                   NULL, NULL,
730                   _gtk_marshal_VOID__BOOLEAN,
731                   GTK_TYPE_NONE, 1,
732                   G_TYPE_BOOLEAN);
733
734   tree_view_signals[TOGGLE_CURSOR_ROW] =
735     g_signal_new ("toggle_cursor_row",
736                   G_TYPE_FROM_CLASS (object_class),
737                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
738                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
739                   NULL, NULL,
740                   _gtk_marshal_NONE__NONE,
741                   GTK_TYPE_NONE, 0);
742
743   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
744     g_signal_new ("expand_collapse_cursor_row",
745                   G_TYPE_FROM_CLASS (object_class),
746                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
747                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
748                   NULL, NULL,
749                   _gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
750                   GTK_TYPE_NONE, 3, GTK_TYPE_BOOL, GTK_TYPE_BOOL, GTK_TYPE_BOOL);
751
752   tree_view_signals[SELECT_CURSOR_PARENT] =
753     g_signal_new ("select_cursor_parent",
754                   G_TYPE_FROM_CLASS (object_class),
755                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
756                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
757                   NULL, NULL,
758                   _gtk_marshal_NONE__NONE,
759                   GTK_TYPE_NONE, 0);
760
761   tree_view_signals[START_INTERACTIVE_SEARCH] =
762     g_signal_new ("start_interactive_search",
763                   G_TYPE_FROM_CLASS (object_class),
764                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
765                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
766                   NULL, NULL,
767                   _gtk_marshal_NONE__NONE,
768                   GTK_TYPE_NONE, 0);
769
770   /* Key bindings */
771   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
772                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
773
774   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
775                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
776
777   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
778                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
779
780   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
781                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
782
783   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
784                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
785
786   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
787                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
788
789   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
790                                   GTK_MOVEMENT_PAGES, -1);
791
792   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
793                                   GTK_MOVEMENT_PAGES, 1);
794
795   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
796                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
797                                 GTK_TYPE_INT, 1);
798
799   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
800                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
801                                 GTK_TYPE_INT, -1);
802
803   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK, "move_cursor", 2,
804                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
805                                 GTK_TYPE_INT, 1);
806
807   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK, "move_cursor", 2,
808                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
809                                 GTK_TYPE_INT, -1);
810
811   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
812                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
813                                 GTK_TYPE_INT, 1);
814
815   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
816                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
817                                 GTK_TYPE_INT, -1);
818
819   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "move_cursor", 2,
820                                 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
821                                 GTK_TYPE_INT, 1);
822
823   gtk_binding_entry_add_signal (binding_set, GDK_b, GDK_CONTROL_MASK, "move_cursor", 2,
824                                 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
825                                 GTK_TYPE_INT, -1);
826
827   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
828
829   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
830
831   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select_cursor_row", 1,
832                                 GTK_TYPE_BOOL, TRUE);
833
834   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
835                                 GTK_TYPE_BOOL, TRUE);
836
837   /* expand and collapse rows */
838   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
839                                 GTK_TYPE_BOOL, FALSE,
840                                 GTK_TYPE_BOOL, TRUE,
841                                 GTK_TYPE_BOOL, FALSE);
842   /* Not doable on US keyboards */
843   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
844                                 GTK_TYPE_BOOL, FALSE,
845                                 GTK_TYPE_BOOL, TRUE,
846                                 GTK_TYPE_BOOL, TRUE);
847   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
848                                 GTK_TYPE_BOOL, FALSE,
849                                 GTK_TYPE_BOOL, TRUE,
850                                 GTK_TYPE_BOOL, FALSE);
851   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
852                                 GTK_TYPE_BOOL, FALSE,
853                                 GTK_TYPE_BOOL, TRUE,
854                                 GTK_TYPE_BOOL, TRUE);
855   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
856                                 GTK_TYPE_BOOL, FALSE,
857                                 GTK_TYPE_BOOL, TRUE,
858                                 GTK_TYPE_BOOL, TRUE);
859   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
860                                 GTK_TYPE_BOOL, TRUE,
861                                 GTK_TYPE_BOOL, TRUE,
862                                 GTK_TYPE_BOOL, TRUE);
863
864   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
865                                 GTK_TYPE_BOOL, FALSE,
866                                 GTK_TYPE_BOOL, FALSE,
867                                 GTK_TYPE_BOOL, FALSE);
868   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
869                                 GTK_TYPE_BOOL, FALSE,
870                                 GTK_TYPE_BOOL, FALSE,
871                                 GTK_TYPE_BOOL, TRUE);
872   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
873                                 GTK_TYPE_BOOL, FALSE,
874                                 GTK_TYPE_BOOL, FALSE,
875                                 GTK_TYPE_BOOL, FALSE);
876   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
877                                 GTK_TYPE_BOOL, FALSE,
878                                 GTK_TYPE_BOOL, FALSE,
879                                 GTK_TYPE_BOOL, TRUE);
880   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
881                                 GTK_TYPE_BOOL, FALSE,
882                                 GTK_TYPE_BOOL, FALSE,
883                                 GTK_TYPE_BOOL, TRUE);
884
885   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
886
887   gtk_binding_entry_add_signal (binding_set, GDK_s, GDK_CONTROL_MASK, "start_interactive_search", 0);
888
889   gtk_binding_entry_add_signal (binding_set, GDK_S, GDK_CONTROL_MASK, "start_interactive_search", 0);
890 }
891
892 static void
893 gtk_tree_view_init (GtkTreeView *tree_view)
894 {
895   tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
896   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
897
898   tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
899
900   /* We need some padding */
901   tree_view->priv->dy = 0;
902   tree_view->priv->n_columns = 0;
903   tree_view->priv->header_height = 1;
904   tree_view->priv->x_drag = 0;
905   tree_view->priv->drag_pos = -1;
906   tree_view->priv->header_has_focus = FALSE;
907   tree_view->priv->pressed_button = -1;
908   tree_view->priv->press_start_x = -1;
909   tree_view->priv->press_start_y = -1;
910   tree_view->priv->reorderable = FALSE;
911   tree_view->priv->presize_handler_timer = 0;
912   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
913   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
914   tree_view->priv->enable_search = TRUE;
915   tree_view->priv->search_column = -1;
916   tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
917   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
918 }
919
920 \f
921
922 /* GObject Methods
923  */
924
925 static void
926 gtk_tree_view_set_property (GObject         *object,
927                             guint            prop_id,
928                             const GValue    *value,
929                             GParamSpec      *pspec)
930 {
931   GtkTreeView *tree_view;
932
933   tree_view = GTK_TREE_VIEW (object);
934
935   switch (prop_id)
936     {
937     case PROP_MODEL:
938       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
939       break;
940     case PROP_HADJUSTMENT:
941       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
942       break;
943     case PROP_VADJUSTMENT:
944       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
945       break;
946     case PROP_HEADERS_VISIBLE:
947       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
948       break;
949     case PROP_HEADERS_CLICKABLE:
950       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
951       break;
952     case PROP_EXPANDER_COLUMN:
953       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
954       break;
955     case PROP_REORDERABLE:
956       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
957       break;
958     case PROP_RULES_HINT:
959       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
960     case PROP_ENABLE_SEARCH:
961       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
962       break;
963     case PROP_SEARCH_COLUMN:
964       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
965       break;
966     default:
967       break;
968     }
969 }
970
971 static void
972 gtk_tree_view_get_property (GObject    *object,
973                             guint       prop_id,
974                             GValue     *value,
975                             GParamSpec *pspec)
976 {
977   GtkTreeView *tree_view;
978
979   tree_view = GTK_TREE_VIEW (object);
980
981   switch (prop_id)
982     {
983     case PROP_MODEL:
984       g_value_set_object (value, tree_view->priv->model);
985       break;
986     case PROP_HADJUSTMENT:
987       g_value_set_object (value, tree_view->priv->hadjustment);
988       break;
989     case PROP_VADJUSTMENT:
990       g_value_set_object (value, tree_view->priv->vadjustment);
991       break;
992     case PROP_HEADERS_VISIBLE:
993       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
994       break;
995     case PROP_EXPANDER_COLUMN:
996       g_value_set_object (value, tree_view->priv->expander_column);
997       break;
998     case PROP_REORDERABLE:
999       g_value_set_boolean (value, tree_view->priv->reorderable);
1000       break;
1001     case PROP_RULES_HINT:
1002       g_value_set_boolean (value, tree_view->priv->has_rules);
1003       break;
1004     case PROP_ENABLE_SEARCH:
1005       g_value_set_boolean (value, tree_view->priv->enable_search);
1006       break;
1007     case PROP_SEARCH_COLUMN:
1008       g_value_set_int (value, tree_view->priv->search_column);
1009       break;
1010     default:
1011       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1012       break;
1013     }
1014 }
1015
1016 static void
1017 gtk_tree_view_finalize (GObject *object)
1018 {
1019   GtkTreeView *tree_view = (GtkTreeView *) object;
1020
1021   g_free (tree_view->priv);
1022
1023   if (G_OBJECT_CLASS (parent_class)->finalize)
1024     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1025 }
1026
1027 \f
1028
1029 /* GtkObject Methods
1030  */
1031
1032 static void
1033 gtk_tree_view_destroy (GtkObject *object)
1034 {
1035   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1036   GtkWidget *search_dialog;
1037   GList *list;
1038
1039   gtk_tree_view_stop_editing (tree_view, TRUE);
1040
1041   if (tree_view->priv->columns != NULL)
1042     {
1043       list = tree_view->priv->columns;
1044       while (list)
1045         {
1046           GtkTreeViewColumn *column;
1047           column = GTK_TREE_VIEW_COLUMN (list->data);
1048           list = list->next;
1049           gtk_tree_view_remove_column (tree_view, column);
1050         }
1051       tree_view->priv->columns = NULL;
1052     }
1053
1054   if (tree_view->priv->tree != NULL)
1055     {
1056       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1057       _gtk_rbtree_free (tree_view->priv->tree);
1058       tree_view->priv->tree = NULL;
1059     }
1060
1061   if (tree_view->priv->selection != NULL)
1062     {
1063       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1064       g_object_unref (tree_view->priv->selection);
1065       tree_view->priv->selection = NULL;
1066     }
1067
1068   if (tree_view->priv->scroll_to_path != NULL)
1069     {
1070       gtk_tree_path_free (tree_view->priv->scroll_to_path);
1071       tree_view->priv->scroll_to_path = NULL;
1072     }
1073
1074   if (tree_view->priv->drag_dest_row != NULL)
1075     {
1076       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1077       tree_view->priv->drag_dest_row = NULL;
1078     }
1079
1080   if (tree_view->priv->top_row != NULL)
1081     {
1082       gtk_tree_row_reference_free (tree_view->priv->top_row);
1083       tree_view->priv->top_row = NULL;
1084     }
1085
1086   if (tree_view->priv->column_drop_func_data &&
1087       tree_view->priv->column_drop_func_data_destroy)
1088     {
1089       (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
1090       tree_view->priv->column_drop_func_data = NULL;
1091     }
1092
1093   if (tree_view->priv->destroy_count_destroy &&
1094       tree_view->priv->destroy_count_data)
1095     {
1096       (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
1097       tree_view->priv->destroy_count_data = NULL;
1098     }
1099
1100   gtk_tree_row_reference_free (tree_view->priv->cursor);
1101   tree_view->priv->cursor = NULL;
1102
1103   gtk_tree_row_reference_free (tree_view->priv->anchor);
1104   tree_view->priv->anchor = NULL;
1105
1106   /* destroy interactive search dialog */
1107   search_dialog = gtk_object_get_data (GTK_OBJECT (tree_view),
1108                                        GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
1109   if (search_dialog)
1110     gtk_tree_view_search_dialog_destroy (search_dialog,
1111                                          tree_view);
1112
1113   if (tree_view->priv->search_user_data)
1114     {
1115       (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
1116       tree_view->priv->search_user_data = NULL;
1117     }
1118
1119   gtk_tree_view_set_model (tree_view, NULL);
1120
1121   if (GTK_OBJECT_CLASS (parent_class)->destroy)
1122     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1123 }
1124
1125 \f
1126
1127 /* GtkWidget Methods
1128  */
1129
1130 /* GtkWidget::map helper */
1131 static void
1132 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1133 {
1134   GList *list;
1135
1136   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1137
1138   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1139     {
1140       GtkTreeViewColumn *column;
1141
1142       for (list = tree_view->priv->columns; list; list = list->next)
1143         {
1144           column = list->data;
1145           if (GTK_WIDGET_VISIBLE (column->button) &&
1146               !GTK_WIDGET_MAPPED (column->button))
1147             gtk_widget_map (column->button);
1148         }
1149       for (list = tree_view->priv->columns; list; list = list->next)
1150         {
1151           column = list->data;
1152           if (column->visible == FALSE)
1153             continue;
1154           if (column->resizable)
1155             {
1156               gdk_window_raise (column->window);
1157               gdk_window_show (column->window);
1158             }
1159           else
1160             gdk_window_hide (column->window);
1161         }
1162       gdk_window_show (tree_view->priv->header_window);
1163     }
1164 }
1165
1166 static void
1167 gtk_tree_view_map (GtkWidget *widget)
1168 {
1169   GList *tmp_list;
1170   GtkTreeView *tree_view;
1171
1172   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1173
1174   tree_view = GTK_TREE_VIEW (widget);
1175
1176   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1177
1178   tmp_list = tree_view->priv->children;
1179   while (tmp_list)
1180     {
1181       GtkTreeViewChild *child = tmp_list->data;
1182       tmp_list = tmp_list->next;
1183
1184       if (GTK_WIDGET_VISIBLE (child->widget))
1185         {
1186           if (!GTK_WIDGET_MAPPED (child->widget))
1187             gtk_widget_map (child->widget);
1188         }
1189     }
1190   gdk_window_show (tree_view->priv->bin_window);
1191
1192   gtk_tree_view_map_buttons (tree_view);
1193
1194   gdk_window_show (widget->window);
1195 }
1196
1197 static void
1198 gtk_tree_view_realize (GtkWidget *widget)
1199 {
1200   GList *tmp_list;
1201   GtkTreeView *tree_view;
1202   GdkGCValues values;
1203   GdkWindowAttr attributes;
1204   gint attributes_mask;
1205
1206   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1207
1208   tree_view = GTK_TREE_VIEW (widget);
1209
1210   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1211
1212   /* Make the main, clipping window */
1213   attributes.window_type = GDK_WINDOW_CHILD;
1214   attributes.x = widget->allocation.x;
1215   attributes.y = widget->allocation.y;
1216   attributes.width = widget->allocation.width;
1217   attributes.height = widget->allocation.height;
1218   attributes.wclass = GDK_INPUT_OUTPUT;
1219   attributes.visual = gtk_widget_get_visual (widget);
1220   attributes.colormap = gtk_widget_get_colormap (widget);
1221   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1222
1223   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1224
1225   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1226                                    &attributes, attributes_mask);
1227   gdk_window_set_user_data (widget->window, widget);
1228
1229   /* Make the window for the tree */
1230   attributes.x = 0;
1231   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1232   attributes.width = tree_view->priv->width;
1233   attributes.height = widget->allocation.height;
1234   attributes.event_mask = GDK_EXPOSURE_MASK |
1235     GDK_SCROLL_MASK |
1236     GDK_POINTER_MOTION_MASK |
1237     GDK_ENTER_NOTIFY_MASK |
1238     GDK_LEAVE_NOTIFY_MASK |
1239     GDK_BUTTON_PRESS_MASK |
1240     GDK_BUTTON_RELEASE_MASK |
1241     gtk_widget_get_events (widget);
1242
1243   tree_view->priv->bin_window = gdk_window_new (widget->window,
1244                                                 &attributes, attributes_mask);
1245   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1246
1247   /* Make the column header window */
1248   attributes.x = 0;
1249   attributes.y = 0;
1250   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1251   attributes.height = tree_view->priv->header_height;
1252   attributes.event_mask = (GDK_EXPOSURE_MASK |
1253                            GDK_SCROLL_MASK |
1254                            GDK_BUTTON_PRESS_MASK |
1255                            GDK_BUTTON_RELEASE_MASK |
1256                            GDK_KEY_PRESS_MASK |
1257                            GDK_KEY_RELEASE_MASK) |
1258     gtk_widget_get_events (widget);
1259
1260   tree_view->priv->header_window = gdk_window_new (widget->window,
1261                                                    &attributes, attributes_mask);
1262   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1263
1264
1265   values.foreground = (widget->style->white.pixel==0 ?
1266                        widget->style->black:widget->style->white);
1267   values.function = GDK_XOR;
1268   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1269
1270   /* Add them all up. */
1271   widget->style = gtk_style_attach (widget->style, widget->window);
1272   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1273   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1274   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1275
1276   tmp_list = tree_view->priv->children;
1277   while (tmp_list)
1278     {
1279       GtkTreeViewChild *child = tmp_list->data;
1280       tmp_list = tmp_list->next;
1281
1282       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1283     }
1284
1285   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1286     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1287
1288   install_presize_handler (tree_view); 
1289 }
1290
1291 static void
1292 gtk_tree_view_unrealize (GtkWidget *widget)
1293 {
1294   GtkTreeView *tree_view;
1295   GList *list;
1296
1297   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1298
1299   tree_view = GTK_TREE_VIEW (widget);
1300
1301   if (tree_view->priv->scroll_timeout != 0)
1302     {
1303       gtk_timeout_remove (tree_view->priv->scroll_timeout);
1304       tree_view->priv->scroll_timeout = 0;
1305     }
1306
1307   if (tree_view->priv->open_dest_timeout != 0)
1308     {
1309       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
1310       tree_view->priv->open_dest_timeout = 0;
1311     }
1312
1313   if (tree_view->priv->expand_collapse_timeout != 0)
1314     {
1315       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
1316       tree_view->priv->expand_collapse_timeout = 0;
1317     }
1318   
1319   if (tree_view->priv->presize_handler_timer != 0)
1320     {
1321       gtk_timeout_remove (tree_view->priv->presize_handler_timer);
1322       tree_view->priv->presize_handler_timer = 0;
1323     }
1324
1325   if (tree_view->priv->validate_rows_timer != 0)
1326     {
1327       gtk_timeout_remove (tree_view->priv->validate_rows_timer);
1328       tree_view->priv->validate_rows_timer = 0;
1329     }
1330
1331   for (list = tree_view->priv->columns; list; list = list->next)
1332     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1333
1334   gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
1335   gdk_window_destroy (tree_view->priv->bin_window);
1336   tree_view->priv->bin_window = NULL;
1337
1338   gdk_window_set_user_data (tree_view->priv->header_window, NULL);
1339   gdk_window_destroy (tree_view->priv->header_window);
1340   tree_view->priv->header_window = NULL;
1341
1342   if (tree_view->priv->drag_window)
1343     {
1344       gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
1345       gdk_window_destroy (tree_view->priv->drag_window);
1346       tree_view->priv->drag_window = NULL;
1347     }
1348
1349   if (tree_view->priv->drag_highlight_window)
1350     {
1351       gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
1352       gdk_window_destroy (tree_view->priv->drag_highlight_window);
1353       tree_view->priv->drag_highlight_window = NULL;
1354     }
1355
1356   /* GtkWidget::unrealize destroys children and widget->window */
1357   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1358     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1359 }
1360
1361 /* GtkWidget::size_request helper */
1362 static void
1363 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1364 {
1365   GList *list;
1366
1367   tree_view->priv->header_height = 0;
1368
1369   if (tree_view->priv->model)
1370     {
1371       for (list = tree_view->priv->columns; list; list = list->next)
1372         {
1373           GtkRequisition requisition;
1374           GtkTreeViewColumn *column = list->data;
1375
1376           if (column->button == NULL)
1377             continue;
1378
1379           column = list->data;
1380           
1381           gtk_widget_size_request (column->button, &requisition);
1382           column->button_request = requisition.width;
1383           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1384         }
1385     }
1386 }
1387
1388
1389 static void
1390 gtk_tree_view_update_size (GtkTreeView *tree_view)
1391 {
1392   GList *list;
1393   GtkTreeViewColumn *column;
1394   gint i;
1395
1396   if (tree_view->priv->model == NULL)
1397     {
1398       tree_view->priv->width = 0;
1399       tree_view->priv->height = 0;
1400       return;
1401     }
1402
1403   tree_view->priv->width = 0;
1404   /* keep this in sync with size_allocate below */
1405   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1406     {
1407       gint real_requested_width = 0;
1408       column = list->data;
1409       if (!column->visible)
1410         continue;
1411
1412       if (column->use_resized_width)
1413         {
1414           real_requested_width = column->resized_width;
1415         }
1416       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1417         {
1418           real_requested_width = column->fixed_width;
1419         }
1420       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1421         {
1422           real_requested_width = MAX (column->requested_width, column->button_request);
1423         }
1424       else
1425         {
1426           real_requested_width = column->requested_width;
1427         }
1428
1429       if (column->min_width != -1)
1430         real_requested_width = MAX (real_requested_width, column->min_width);
1431       if (column->max_width != -1)
1432         real_requested_width = MIN (real_requested_width, column->max_width);
1433
1434       tree_view->priv->width += real_requested_width;
1435     }
1436
1437   if (tree_view->priv->tree == NULL)
1438     tree_view->priv->height = 0;
1439   else
1440     tree_view->priv->height = tree_view->priv->tree->root->offset;
1441 }
1442
1443 static void
1444 gtk_tree_view_size_request (GtkWidget      *widget,
1445                             GtkRequisition *requisition)
1446 {
1447   GtkTreeView *tree_view;
1448   GList *tmp_list;
1449
1450   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1451
1452   tree_view = GTK_TREE_VIEW (widget);
1453
1454   /* we validate 50 rows initially just to make sure we have some size */
1455   /* in practice, with a lot of static lists, this should get a good width */
1456   validate_rows_handler (tree_view);
1457   gtk_tree_view_size_request_columns (tree_view);
1458   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1459
1460   requisition->width = tree_view->priv->width;
1461   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
1462
1463   tmp_list = tree_view->priv->children;
1464
1465   while (tmp_list)
1466     {
1467       GtkTreeViewChild *child = tmp_list->data;
1468       GtkRequisition child_requisition;
1469
1470       tmp_list = tmp_list->next;
1471
1472       if (GTK_WIDGET_VISIBLE (child->widget))
1473         gtk_widget_size_request (child->widget, &child_requisition);
1474     }
1475 }
1476
1477 /* GtkWidget::size_allocate helper */
1478 static void
1479 gtk_tree_view_size_allocate_columns (GtkWidget *widget)
1480 {
1481   GtkTreeView *tree_view;
1482   GList *list, *last_column;
1483   GtkTreeViewColumn *column;
1484   GtkAllocation allocation;
1485   gint width = 0;
1486
1487   tree_view = GTK_TREE_VIEW (widget);
1488
1489   for (last_column = g_list_last (tree_view->priv->columns);
1490        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
1491        last_column = last_column->prev)
1492     ;
1493   if (last_column == NULL)
1494     return;
1495
1496   allocation.y = 0;
1497   allocation.height = tree_view->priv->header_height;
1498
1499   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
1500     {
1501       gint real_requested_width = 0;
1502       column = list->data;
1503       if (!column->visible)
1504         continue;
1505
1506       /* We need to handle the dragged button specially.
1507        */
1508       if (column == tree_view->priv->drag_column)
1509         {
1510           GtkAllocation drag_allocation;
1511           gdk_window_get_size (tree_view->priv->drag_window,
1512                                &(drag_allocation.width), &(drag_allocation.height));
1513           drag_allocation.x = 0;
1514           drag_allocation.y = 0;
1515           gtk_widget_size_allocate (tree_view->priv->drag_column->button, &drag_allocation);
1516           width += drag_allocation.width;
1517           continue;
1518         }
1519
1520       if (column->use_resized_width)
1521         {
1522           real_requested_width = column->resized_width;
1523         }
1524       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1525         {
1526           real_requested_width = column->fixed_width;
1527         }
1528       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1529         {
1530           real_requested_width = MAX (column->requested_width, column->button_request);
1531         }
1532       else
1533         {
1534           real_requested_width = column->requested_width;
1535           if (real_requested_width < 0)
1536             real_requested_width = 0;
1537         }
1538
1539       if (column->min_width != -1)
1540         real_requested_width = MAX (real_requested_width, column->min_width);
1541       if (column->max_width != -1)
1542         real_requested_width = MIN (real_requested_width, column->max_width);
1543
1544       allocation.x = width;
1545       column->width = real_requested_width;
1546       if (list == last_column &&
1547           width + real_requested_width < widget->allocation.width)
1548         {
1549           column->width += (widget->allocation.width - column->width - width);
1550         }
1551       g_object_notify (G_OBJECT (column), "width");
1552       allocation.width = column->width;
1553       width += column->width;
1554       gtk_widget_size_allocate (column->button, &allocation);
1555       if (column->window)
1556         gdk_window_move_resize (column->window,
1557                                 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
1558                                 allocation.y,
1559                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
1560     }
1561 }
1562
1563 static void
1564 gtk_tree_view_size_allocate (GtkWidget     *widget,
1565                              GtkAllocation *allocation)
1566 {
1567   GList *tmp_list;
1568   GtkTreeView *tree_view;
1569
1570   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1571
1572   widget->allocation = *allocation;
1573
1574   tree_view = GTK_TREE_VIEW (widget);
1575
1576   tmp_list = tree_view->priv->children;
1577
1578   while (tmp_list)
1579     {
1580       GtkAllocation allocation;
1581
1582       GtkTreeViewChild *child = tmp_list->data;
1583       tmp_list = tmp_list->next;
1584
1585       /* totally ignore our childs requisition */
1586       allocation.x = child->x;
1587       allocation.y = child->y;
1588       allocation.width = child->width;
1589       allocation.height = child->height;
1590       gtk_widget_size_allocate (child->widget, &allocation);
1591     }
1592
1593
1594   tree_view->priv->hadjustment->page_size = allocation->width;
1595   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
1596   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
1597   tree_view->priv->hadjustment->lower = 0;
1598   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
1599
1600   if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
1601     tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
1602   gtk_adjustment_changed (tree_view->priv->hadjustment);
1603
1604   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
1605   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
1606   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
1607   tree_view->priv->vadjustment->lower = 0;
1608   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
1609
1610   if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
1611     gtk_adjustment_set_value (tree_view->priv->vadjustment,
1612                               MAX (tree_view->priv->height - tree_view->priv->vadjustment->page_size, 0));
1613   gtk_adjustment_changed (tree_view->priv->vadjustment);
1614   
1615   if (GTK_WIDGET_REALIZED (widget))
1616     {
1617       gdk_window_move_resize (widget->window,
1618                               allocation->x, allocation->y,
1619                               allocation->width, allocation->height);
1620       gdk_window_move_resize (tree_view->priv->header_window,
1621                               - (gint) tree_view->priv->hadjustment->value,
1622                               0,
1623                               MAX (tree_view->priv->width, allocation->width),
1624                               tree_view->priv->header_height);
1625       gdk_window_move_resize (tree_view->priv->bin_window,
1626                               - (gint) tree_view->priv->hadjustment->value,
1627                               TREE_VIEW_HEADER_HEIGHT (tree_view),
1628                               MAX (tree_view->priv->width, allocation->width),
1629                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
1630     }
1631
1632   gtk_tree_view_size_allocate_columns (widget);
1633   
1634   if (tree_view->priv->scroll_to_path != NULL ||
1635       tree_view->priv->scroll_to_column != NULL)
1636     {
1637       gtk_tree_view_scroll_to_cell (tree_view,
1638                                     tree_view->priv->scroll_to_path,
1639                                     tree_view->priv->scroll_to_column,
1640                                     tree_view->priv->scroll_to_use_align,
1641                                     tree_view->priv->scroll_to_row_align,
1642                                     tree_view->priv->scroll_to_col_align);
1643       if (tree_view->priv->scroll_to_path)
1644         {
1645           gtk_tree_path_free (tree_view->priv->scroll_to_path);
1646           tree_view->priv->scroll_to_path = NULL;
1647         }
1648       tree_view->priv->scroll_to_column = NULL;
1649     }
1650 }
1651
1652 static gboolean
1653 gtk_tree_view_button_press (GtkWidget      *widget,
1654                             GdkEventButton *event)
1655 {
1656   GtkTreeView *tree_view;
1657   GList *list;
1658   GtkTreeViewColumn *column = NULL;
1659   gint i;
1660   GdkRectangle background_area;
1661   GdkRectangle cell_area;
1662   gint vertical_separator;
1663   gint horizontal_separator;
1664
1665   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1666   g_return_val_if_fail (event != NULL, FALSE);
1667
1668   tree_view = GTK_TREE_VIEW (widget);
1669   gtk_tree_view_stop_editing (tree_view, FALSE);
1670   gtk_widget_style_get (widget,
1671                         "vertical_separator", &vertical_separator,
1672                         "horizontal_separator", &horizontal_separator,
1673                         NULL);
1674
1675   if (event->window == tree_view->priv->bin_window &&
1676       tree_view->priv->tree != NULL)
1677     {
1678       GtkRBNode *node;
1679       GtkRBTree *tree;
1680       GtkTreePath *path;
1681       gchar *path_string;
1682       gint depth;
1683       gint new_y;
1684       gint y_offset;
1685       gint dval;
1686       gint pre_val, aft_val;
1687       GtkTreeViewColumn *column = NULL;
1688       gint column_handled_click = FALSE;
1689
1690       if (!GTK_WIDGET_HAS_FOCUS (widget))
1691         gtk_widget_grab_focus (widget);
1692       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1693
1694       /* are we in an arrow? */
1695       if (tree_view->priv->prelight_node &&
1696           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1697         {
1698           if (event->button == 1)
1699             {
1700               gtk_grab_add (widget);
1701               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1702               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1703               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1704                                         tree_view->priv->prelight_tree,
1705                                         tree_view->priv->prelight_node,
1706                                         event->x,
1707                                         event->y);
1708             }
1709           return TRUE;
1710         }
1711
1712       /* find the node that was clicked */
1713       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
1714       if (new_y < 0)
1715         new_y = 0;
1716       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
1717
1718       if (node == NULL)
1719         /* We clicked in dead space */
1720         return TRUE;
1721
1722       /* Get the path and the node */
1723       path = _gtk_tree_view_find_path (tree_view, tree, node);
1724       depth = gtk_tree_path_get_depth (path);
1725       background_area.y = y_offset + event->y;
1726       background_area.height = MAX (GTK_RBNODE_GET_HEIGHT (node),
1727                                     tree_view->priv->expander_size);
1728       background_area.x = 0;
1729
1730       /* Let the column have a chance at selecting it. */
1731       for (list = tree_view->priv->columns; list; list = list->next)
1732         {
1733           column = list->data;
1734
1735           if (!column->visible)
1736             continue;
1737
1738           background_area.width = column->width;
1739           if ((background_area.x > (gint) event->x) ||
1740               (background_area.x + background_area.width <= (gint) event->x))
1741             {
1742               background_area.x += background_area.width;
1743               continue;
1744             }
1745
1746           /* we found the focus column */
1747           cell_area = background_area;
1748           cell_area.width -= horizontal_separator;
1749           cell_area.height -= vertical_separator;
1750           cell_area.x += horizontal_separator/2;
1751           cell_area.y += vertical_separator/2;
1752           if (gtk_tree_view_is_expander_column (tree_view, column) &&
1753               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1754             {
1755               cell_area.x += depth * tree_view->priv->expander_size;
1756               cell_area.width -= depth * tree_view->priv->expander_size;
1757             }
1758           break;
1759         }
1760
1761       if (column == NULL)
1762         return FALSE;
1763
1764       pre_val = tree_view->priv->vadjustment->value;
1765
1766       tree_view->priv->focus_column = column;
1767       if (event->state & GDK_CONTROL_MASK)
1768         {
1769           gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
1770           gtk_tree_view_real_toggle_cursor_row (tree_view);
1771         }
1772       else if (event->state & GDK_SHIFT_MASK)
1773         {
1774           gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
1775           gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
1776         }
1777       else
1778         {
1779           gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
1780         }
1781
1782       /* the treeview may have been scrolled because of _set_cursor,
1783        * correct here
1784        */
1785
1786       aft_val = tree_view->priv->vadjustment->value;
1787       dval = pre_val - aft_val;
1788
1789       cell_area.y += dval;
1790       background_area.y += dval;
1791
1792       if (event->type == GDK_BUTTON_PRESS &&
1793           !(event->state & gtk_accelerator_get_default_mod_mask ()))
1794         {
1795           GtkCellEditable *cell_editable = NULL;
1796           /* FIXME: get the right flags */
1797           guint flags = 0;
1798           GtkTreeIter iter;
1799
1800           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1801           gtk_tree_view_column_cell_set_cell_data (column,
1802                                                    tree_view->priv->model,
1803                                                    &iter,
1804                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
1805                                                    node->children?TRUE:FALSE);
1806
1807           path_string = gtk_tree_path_to_string (path);
1808
1809           if (_gtk_tree_view_column_cell_event (column,
1810                                                 &cell_editable,
1811                                                 (GdkEvent *)event,
1812                                                 path_string,
1813                                                 &background_area,
1814                                                 &cell_area, flags))
1815             {
1816               if (cell_editable != NULL)
1817                 {
1818                   gtk_tree_view_real_start_editing (tree_view,
1819                                                     column,
1820                                                     path,
1821                                                     cell_editable,
1822                                                     &cell_area,
1823                                                     (GdkEvent *)event,
1824                                                     flags);
1825
1826                 }
1827               column_handled_click = TRUE;
1828             }
1829           g_free (path_string);
1830         }
1831
1832       /* Save press to possibly begin a drag
1833        */
1834       if (!column_handled_click &&
1835           tree_view->priv->pressed_button < 0)
1836         {
1837           tree_view->priv->pressed_button = event->button;
1838           tree_view->priv->press_start_x = event->x;
1839           tree_view->priv->press_start_y = event->y;
1840         }
1841
1842       if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1843         {
1844           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
1845             {
1846               if (node->children == NULL)
1847                 gtk_tree_view_real_expand_row (tree_view, path,
1848                                                tree, node, FALSE, TRUE);
1849               else
1850                 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1851                                                  tree, node, TRUE);
1852             }
1853
1854           gtk_tree_view_row_activated (tree_view, path, column);
1855         }
1856       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1857       gtk_tree_path_free (path);
1858       return TRUE;
1859     }
1860
1861   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
1862    */
1863   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1864     {
1865       column = list->data;
1866       if (event->window == column->window &&
1867           column->resizable &&
1868           column->window)
1869         {
1870           gpointer drag_data;
1871
1872           if (gdk_pointer_grab (column->window, FALSE,
1873                                 GDK_POINTER_MOTION_HINT_MASK |
1874                                 GDK_BUTTON1_MOTION_MASK |
1875                                 GDK_BUTTON_RELEASE_MASK,
1876                                 NULL, NULL, event->time))
1877             return FALSE;
1878
1879           gtk_grab_add (widget);
1880           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1881           column->resized_width = column->width;
1882           column->use_resized_width = TRUE;
1883
1884           /* block attached dnd signal handler */
1885           drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1886           if (drag_data)
1887             gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1888
1889           if (!GTK_WIDGET_HAS_FOCUS (widget))
1890             gtk_widget_grab_focus (widget);
1891
1892           tree_view->priv->drag_pos = i;
1893           tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1894           break;
1895         }
1896     }
1897   return TRUE;
1898 }
1899
1900 /* GtkWidget::button_release_event helper */
1901 static gboolean
1902 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
1903                                           GdkEventButton *event)
1904 {
1905   GtkTreeView *tree_view;
1906
1907   tree_view = GTK_TREE_VIEW (widget);
1908
1909   gdk_pointer_ungrab (GDK_CURRENT_TIME);
1910   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
1911
1912   /* Move the button back */
1913   g_object_ref (tree_view->priv->drag_column->button);
1914   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
1915   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
1916   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
1917   g_object_unref (tree_view->priv->drag_column->button);
1918   gtk_widget_queue_resize (widget);
1919   if (tree_view->priv->drag_column->resizable)
1920     {
1921       gdk_window_raise (tree_view->priv->drag_column->window);
1922       gdk_window_show (tree_view->priv->drag_column->window);
1923     }
1924   else
1925     gdk_window_hide (tree_view->priv->drag_column->window);
1926
1927   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
1928
1929   if (tree_view->priv->cur_reorder &&
1930       tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
1931     gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
1932                                      tree_view->priv->cur_reorder->left_column);
1933   tree_view->priv->drag_column = NULL;
1934   gdk_window_hide (tree_view->priv->drag_window);
1935
1936   g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
1937   g_list_free (tree_view->priv->column_drag_info);
1938   tree_view->priv->column_drag_info = NULL;
1939
1940   gdk_window_hide (tree_view->priv->drag_highlight_window);
1941
1942   /* Reset our flags */
1943   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
1944   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
1945
1946   return TRUE;
1947 }
1948
1949 /* GtkWidget::button_release_event helper */
1950 static gboolean
1951 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
1952                                             GdkEventButton *event)
1953 {
1954   GtkTreeView *tree_view;
1955   gpointer drag_data;
1956   gint x;
1957   gint i;
1958
1959   tree_view = GTK_TREE_VIEW (widget);
1960
1961   i = tree_view->priv->drag_pos;
1962   tree_view->priv->drag_pos = -1;
1963
1964       /* unblock attached dnd signal handler */
1965   drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1966   if (drag_data)
1967     gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1968
1969   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1970   gtk_widget_get_pointer (widget, &x, NULL);
1971   gtk_grab_remove (widget);
1972   gdk_pointer_ungrab (event->time);
1973
1974   return TRUE;
1975 }
1976
1977 static gboolean
1978 gtk_tree_view_button_release (GtkWidget      *widget,
1979                               GdkEventButton *event)
1980 {
1981   GtkTreeView *tree_view;
1982
1983   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1984   g_return_val_if_fail (event != NULL, FALSE);
1985
1986   tree_view = GTK_TREE_VIEW (widget);
1987
1988   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
1989     return gtk_tree_view_button_release_drag_column (widget, event);
1990
1991   if (tree_view->priv->pressed_button == event->button)
1992     tree_view->priv->pressed_button = -1;
1993
1994   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1995     return gtk_tree_view_button_release_column_resize (widget, event);
1996
1997   if (tree_view->priv->button_pressed_node == NULL)
1998     return FALSE;
1999
2000   if (event->button == 1)
2001     {
2002       gtk_grab_remove (widget);
2003       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
2004           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2005         {
2006           GtkTreePath *path = NULL;
2007
2008           path = _gtk_tree_view_find_path (tree_view,
2009                                            tree_view->priv->button_pressed_tree,
2010                                            tree_view->priv->button_pressed_node);
2011           /* Actually activate the node */
2012           if (tree_view->priv->button_pressed_node->children == NULL)
2013             gtk_tree_view_real_expand_row (tree_view, path,
2014                                            tree_view->priv->button_pressed_tree,
2015                                            tree_view->priv->button_pressed_node,
2016                                            FALSE, TRUE);
2017           else
2018             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
2019                                              tree_view->priv->button_pressed_tree,
2020                                              tree_view->priv->button_pressed_node, TRUE);
2021           gtk_tree_path_free (path);
2022         }
2023
2024       tree_view->priv->button_pressed_tree = NULL;
2025       tree_view->priv->button_pressed_node = NULL;
2026     }
2027
2028   return TRUE;
2029 }
2030
2031
2032 /* GtkWidget::motion_event function set.
2033  */
2034
2035 static gboolean
2036 coords_are_over_arrow (GtkTreeView *tree_view,
2037                        GtkRBTree   *tree,
2038                        GtkRBNode   *node,
2039                        /* these are in window coords */
2040                        gint         x,
2041                        gint         y)
2042 {
2043   GdkRectangle arrow;
2044   gint x2;
2045
2046   if (!GTK_WIDGET_REALIZED (tree_view))
2047     return FALSE;
2048
2049   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
2050     return FALSE;
2051
2052   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2053
2054   arrow.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
2055
2056   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
2057
2058   arrow.width = x2 - arrow.x;
2059
2060   return (x >= arrow.x &&
2061           x < (arrow.x + arrow.width) &&
2062           y >= arrow.y &&
2063           y < (arrow.y + arrow.height));
2064 }
2065
2066 static void
2067 do_unprelight (GtkTreeView *tree_view,
2068                /* these are in tree window coords */
2069                gint x,
2070                gint y)
2071 {
2072   if (tree_view->priv->prelight_node == NULL)
2073     return;
2074
2075   GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
2076
2077   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2078       !coords_are_over_arrow (tree_view,
2079                               tree_view->priv->prelight_tree,
2080                               tree_view->priv->prelight_node,
2081                               x,
2082                               y))
2083     /* We need to unprelight the old arrow. */
2084     {
2085       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
2086
2087       gtk_tree_view_draw_arrow (tree_view,
2088                                 tree_view->priv->prelight_tree,
2089                                 tree_view->priv->prelight_node,
2090                                 x,
2091                                 y);
2092
2093     }
2094
2095   tree_view->priv->prelight_node = NULL;
2096   tree_view->priv->prelight_tree = NULL;
2097 }
2098
2099 static void
2100 do_prelight (GtkTreeView *tree_view,
2101              GtkRBTree   *tree,
2102              GtkRBNode   *node,
2103              /* these are in tree_window coords */
2104              gint         x,
2105              gint         y)
2106 {
2107   if (coords_are_over_arrow (tree_view, tree, node, x, y))
2108     {
2109       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
2110     }
2111
2112   tree_view->priv->prelight_node = node;
2113   tree_view->priv->prelight_tree = tree;
2114
2115   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
2116 }
2117
2118 static void
2119 ensure_unprelighted (GtkTreeView *tree_view)
2120 {
2121   do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
2122   g_assert (tree_view->priv->prelight_node == NULL);
2123 }
2124
2125
2126
2127
2128 /* Our motion arrow is either a box (in the case of the original spot)
2129  * or an arrow.  It is expander_size wide.
2130  */
2131 /*
2132  * 11111111111111
2133  * 01111111111110
2134  * 00111111111100
2135  * 00011111111000
2136  * 00001111110000
2137  * 00000111100000
2138  * 00000111100000
2139  * 00000111100000
2140  * ~ ~ ~ ~ ~ ~ ~
2141  * 00000111100000
2142  * 00000111100000
2143  * 00000111100000
2144  * 00001111110000
2145  * 00011111111000
2146  * 00111111111100
2147  * 01111111111110
2148  * 11111111111111
2149  */
2150
2151 static void
2152 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
2153 {
2154   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
2155   GtkWidget *widget = GTK_WIDGET (tree_view);
2156   GdkBitmap *mask = NULL;
2157   gint x;
2158   gint y;
2159   gint width;
2160   gint height;
2161   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
2162   GdkWindowAttr attributes;
2163   guint attributes_mask;
2164
2165   if (!reorder ||
2166       reorder->left_column == tree_view->priv->drag_column ||
2167       reorder->right_column == tree_view->priv->drag_column)
2168     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
2169   else if (reorder->left_column || reorder->right_column)
2170     {
2171       GdkRectangle visible_rect;
2172       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2173       if (reorder->left_column)
2174         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
2175       else
2176         x = reorder->right_column->button->allocation.x;
2177
2178       if (x < visible_rect.x)
2179         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
2180       else if (x > visible_rect.x + visible_rect.width)
2181         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
2182       else
2183         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
2184     }
2185
2186   /* We want to draw the rectangle over the initial location. */
2187   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
2188     {
2189       GdkGC *gc;
2190       GdkColor col;
2191
2192       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
2193         {
2194
2195           if (tree_view->priv->drag_highlight_window)
2196             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2197
2198           attributes.window_type = GDK_WINDOW_CHILD;
2199           attributes.wclass = GDK_INPUT_OUTPUT;
2200           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2201           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2202           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2203           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2204           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
2205           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2206
2207           width = tree_view->priv->drag_column->button->allocation.width;
2208           height = tree_view->priv->drag_column->button->allocation.height;
2209           gdk_window_move_resize (tree_view->priv->drag_highlight_window,
2210                                   tree_view->priv->drag_column_x, 0, width, height);
2211
2212           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2213           gc = gdk_gc_new (mask);
2214           col.pixel = 1;
2215           gdk_gc_set_foreground (gc, &col);
2216           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2217           col.pixel = 0;
2218           gdk_gc_set_foreground(gc, &col);
2219           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
2220           gdk_gc_destroy (gc);
2221
2222           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2223                                          mask, 0, 0);
2224           if (mask) gdk_pixmap_unref (mask);
2225           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
2226         }
2227     }
2228   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
2229     {
2230       gint i, j = 1;
2231       GdkGC *gc;
2232       GdkColor col;
2233
2234       width = tree_view->priv->expander_size;
2235
2236       /* Get x, y, width, height of arrow */
2237       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
2238       if (reorder->left_column)
2239         {
2240           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
2241           height = reorder->left_column->button->allocation.height;
2242         }
2243       else
2244         {
2245           x += reorder->right_column->button->allocation.x - width/2;
2246           height = reorder->right_column->button->allocation.height;
2247         }
2248       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
2249       height += tree_view->priv->expander_size;
2250
2251       /* Create the new window */
2252       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
2253         {
2254           if (tree_view->priv->drag_highlight_window)
2255             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2256
2257           attributes.window_type = GDK_WINDOW_TEMP;
2258           attributes.wclass = GDK_INPUT_OUTPUT;
2259           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2260           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2261           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2262           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2263           attributes.width = width;
2264           attributes.height = height;
2265           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2266           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2267
2268           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2269           gc = gdk_gc_new (mask);
2270           col.pixel = 1;
2271           gdk_gc_set_foreground (gc, &col);
2272           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2273
2274           /* Draw the 2 arrows as per above */
2275           col.pixel = 0;
2276           gdk_gc_set_foreground (gc, &col);
2277           for (i = 0; i < width; i ++)
2278             {
2279               if (i == (width/2 - 1))
2280                 continue;
2281               gdk_draw_line (mask, gc, i, j, i, height - j);
2282               if (i < (width/2 - 1))
2283                 j++;
2284               else
2285                 j--;
2286             }
2287           gdk_gc_destroy (gc);
2288           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2289                                          mask, 0, 0);
2290           if (mask) gdk_pixmap_unref (mask);
2291         }
2292
2293       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
2294       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2295     }
2296   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
2297            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2298     {
2299       gint i, j = 1;
2300       GdkGC *gc;
2301       GdkColor col;
2302
2303       width = tree_view->priv->expander_size;
2304
2305       /* Get x, y, width, height of arrow */
2306       width = width/2; /* remember, the arrow only takes half the available width */
2307       gdk_window_get_origin (widget->window, &x, &y);
2308       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2309         x += widget->allocation.width - width;
2310
2311       if (reorder->left_column)
2312         height = reorder->left_column->button->allocation.height;
2313       else
2314         height = reorder->right_column->button->allocation.height;
2315
2316       y -= tree_view->priv->expander_size;
2317       height += 2*tree_view->priv->expander_size;
2318
2319       /* Create the new window */
2320       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
2321           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2322         {
2323           if (tree_view->priv->drag_highlight_window)
2324             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2325
2326           attributes.window_type = GDK_WINDOW_TEMP;
2327           attributes.wclass = GDK_INPUT_OUTPUT;
2328           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2329           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2330           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2331           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2332           attributes.width = width;
2333           attributes.height = height;
2334           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2335           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2336
2337           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2338           gc = gdk_gc_new (mask);
2339           col.pixel = 1;
2340           gdk_gc_set_foreground (gc, &col);
2341           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2342
2343           /* Draw the 2 arrows as per above */
2344           col.pixel = 0;
2345           gdk_gc_set_foreground (gc, &col);
2346           j = tree_view->priv->expander_size;
2347           for (i = 0; i < width; i ++)
2348             {
2349               gint k;
2350               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
2351                 k = width - i - 1;
2352               else
2353                 k = i;
2354               gdk_draw_line (mask, gc, k, j, k, height - j);
2355               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
2356               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
2357               j--;
2358             }
2359           gdk_gc_destroy (gc);
2360           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2361                                          mask, 0, 0);
2362           if (mask) gdk_pixmap_unref (mask);
2363         }
2364
2365       tree_view->priv->drag_column_window_state = arrow_type;
2366       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2367    }
2368   else
2369     {
2370       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
2371       gdk_window_hide (tree_view->priv->drag_highlight_window);
2372       return;
2373     }
2374
2375   gdk_window_show (tree_view->priv->drag_highlight_window);
2376   gdk_window_raise (tree_view->priv->drag_highlight_window);
2377 }
2378
2379 static gboolean
2380 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
2381                                     GdkEventMotion *event)
2382 {
2383   gint x;
2384   gint new_width;
2385   GtkTreeViewColumn *column;
2386   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2387
2388   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
2389
2390   if (event->is_hint || event->window != widget->window)
2391     gtk_widget_get_pointer (widget, &x, NULL);
2392   else
2393     x = event->x;
2394
2395   if (tree_view->priv->hadjustment)
2396     x += tree_view->priv->hadjustment->value;
2397
2398   new_width = gtk_tree_view_new_column_width (tree_view,
2399                                               tree_view->priv->drag_pos, &x);
2400   if (x != tree_view->priv->x_drag &&
2401       (new_width != column->fixed_width));
2402     {
2403       column->resized_width = new_width;
2404       gtk_widget_queue_resize (widget);
2405     }
2406
2407   return FALSE;
2408 }
2409
2410
2411 static void
2412 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
2413 {
2414   GtkTreeViewColumnReorder *reorder = NULL;
2415   GList *list;
2416   gint mouse_x;
2417
2418   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
2419
2420   for (list = tree_view->priv->column_drag_info; list; list = list->next)
2421     {
2422       reorder = (GtkTreeViewColumnReorder *) list->data;
2423       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
2424         break;
2425       reorder = NULL;
2426     }
2427
2428   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
2429       return;*/
2430
2431   tree_view->priv->cur_reorder = reorder;
2432   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
2433 }
2434
2435 static void
2436 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
2437 {
2438   GdkRectangle visible_rect;
2439   gint y;
2440   gint offset;
2441   gfloat value;
2442
2443   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
2444   y += tree_view->priv->dy;
2445
2446   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2447
2448   /* see if we are near the edge. */
2449   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
2450   if (offset > 0)
2451     {
2452       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
2453       if (offset < 0)
2454         return;
2455     }
2456
2457   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
2458                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
2459   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
2460 }
2461
2462 static gboolean
2463 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
2464 {
2465   GdkRectangle visible_rect;
2466   gint x;
2467   gint offset;
2468   gfloat value;
2469
2470   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
2471
2472   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2473
2474   /* See if we are near the edge. */
2475   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
2476   if (offset > 0)
2477     {
2478       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
2479       if (offset < 0)
2480         return TRUE;
2481     }
2482   offset = offset/3;
2483
2484   value = CLAMP (tree_view->priv->hadjustment->value + offset,
2485                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
2486   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
2487
2488   return TRUE;
2489
2490 }
2491
2492 static gboolean
2493 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
2494                                   GdkEventMotion *event)
2495 {
2496   GtkTreeView *tree_view = (GtkTreeView *) widget;
2497   GtkTreeViewColumn *column = tree_view->priv->drag_column;
2498   gint x, y;
2499
2500   /* Sanity Check */
2501   if ((column == NULL) ||
2502       (event->window != tree_view->priv->drag_window))
2503     return FALSE;
2504
2505   /* Handle moving the header */
2506   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
2507   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
2508              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
2509   gdk_window_move (tree_view->priv->drag_window, x, y);
2510
2511   /* autoscroll, if needed */
2512   gtk_tree_view_horizontal_autoscroll (tree_view);
2513   /* Update the current reorder position and arrow; */
2514   gtk_tree_view_update_current_reorder (tree_view);
2515
2516   return TRUE;
2517 }
2518
2519 static gboolean
2520 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
2521                                  GdkEventMotion *event)
2522 {
2523   GtkTreeView *tree_view;
2524   GtkRBTree *tree;
2525   GtkRBNode *node;
2526   gint new_y;
2527   GtkRBTree *old_prelight_tree;
2528   GtkRBNode *old_prelight_node;
2529   gboolean old_arrow_prelit;
2530
2531   tree_view = (GtkTreeView *) widget;
2532
2533   if (tree_view->priv->tree == NULL)
2534     return FALSE;
2535
2536   gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
2537
2538   old_prelight_tree = tree_view->priv->prelight_tree;
2539   old_prelight_node = tree_view->priv->prelight_node;
2540   old_arrow_prelit = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
2541
2542   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2543   if (new_y < 0)
2544     new_y = 0;
2545   do_unprelight (tree_view, event->x, event->y);
2546   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2547
2548   if (tree == NULL)
2549     return TRUE;
2550
2551   /* If we are currently pressing down a button, we don't want to prelight anything else. */
2552   if ((tree_view->priv->button_pressed_node != NULL) &&
2553       (tree_view->priv->button_pressed_node != node))
2554     return TRUE;
2555
2556
2557   do_prelight (tree_view, tree, node, event->x, event->y);
2558
2559   if (old_prelight_node != tree_view->priv->prelight_node)
2560     {
2561       if (old_prelight_node)
2562         {
2563           _gtk_tree_view_queue_draw_node (tree_view,
2564                                           old_prelight_tree,
2565                                           old_prelight_node,
2566                                           NULL);
2567         }
2568       if (tree_view->priv->prelight_node)
2569         {
2570           _gtk_tree_view_queue_draw_node (tree_view,
2571                                           tree_view->priv->prelight_tree,
2572                                           tree_view->priv->prelight_node,
2573                                           NULL);
2574         }
2575     }
2576   else if (old_arrow_prelit != GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2577     {
2578       if (tree_view->priv->prelight_node)
2579         {
2580           _gtk_tree_view_queue_draw_node (tree_view,
2581                                          tree_view->priv->prelight_tree,
2582                                          tree_view->priv->prelight_node,
2583                                          NULL);
2584         }
2585     }
2586   return TRUE;
2587 }
2588
2589 static gboolean
2590 gtk_tree_view_motion (GtkWidget      *widget,
2591                       GdkEventMotion *event)
2592 {
2593   GtkTreeView *tree_view;
2594
2595   tree_view = (GtkTreeView *) widget;
2596
2597   /* Resizing a column */
2598   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2599     return gtk_tree_view_motion_resize_column (widget, event);
2600
2601   /* Drag column */
2602   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2603     return gtk_tree_view_motion_drag_column (widget, event);
2604
2605   /* Sanity check it */
2606   if (event->window == tree_view->priv->bin_window)
2607     return gtk_tree_view_motion_bin_window (widget, event);
2608
2609   return FALSE;
2610 }
2611
2612 /* Warning: Very scary function.
2613  * Modify at your own risk
2614  *
2615  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
2616  * FIXME: It's not...
2617  */
2618 static gboolean
2619 gtk_tree_view_bin_expose (GtkWidget      *widget,
2620                           GdkEventExpose *event)
2621 {
2622   GtkTreeView *tree_view;
2623   GtkTreePath *path;
2624   GtkRBTree *tree;
2625   GList *list;
2626   GtkRBNode *node;
2627   GtkRBNode *cursor = NULL;
2628   GtkRBTree *cursor_tree = NULL;
2629   GtkRBNode *drag_highlight = NULL;
2630   GtkRBTree *drag_highlight_tree = NULL;
2631   GtkTreeIter iter;
2632   gint new_y;
2633   gint y_offset, x_offset, cell_offset;
2634   gint max_height;
2635   gint depth;
2636   GdkRectangle background_area;
2637   GdkRectangle cell_area;
2638   guint flags;
2639   gint highlight_x;
2640   gint bin_window_width;
2641   GtkTreePath *cursor_path;
2642   GtkTreePath *drag_dest_path;
2643   GList *last_column;
2644   gint vertical_separator;
2645   gint horizontal_separator;
2646   gboolean allow_rules;
2647
2648   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2649
2650   tree_view = GTK_TREE_VIEW (widget);
2651
2652   gtk_widget_style_get (widget,
2653                         "horizontal_separator", &horizontal_separator,
2654                         "vertical_separator", &vertical_separator,
2655                         "allow_rules", &allow_rules,
2656                         NULL);
2657
2658   if (tree_view->priv->tree == NULL)
2659     return TRUE;
2660
2661   /* clip event->area to the visible area */
2662   if (event->area.height < 0)
2663     return TRUE;
2664
2665   validate_visible_area (tree_view);
2666
2667   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
2668
2669   if (new_y < 0)
2670     new_y = 0;
2671   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2672
2673   if (node == NULL)
2674     return TRUE;
2675
2676   /* find the path for the node */
2677   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
2678                                    tree,
2679                                    node);
2680   gtk_tree_model_get_iter (tree_view->priv->model,
2681                            &iter,
2682                            path);
2683   depth = gtk_tree_path_get_depth (path);
2684   gtk_tree_path_free (path);
2685
2686   cursor_path = NULL;
2687   drag_dest_path = NULL;
2688
2689   if (tree_view->priv->cursor)
2690     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2691
2692   if (cursor_path)
2693     _gtk_tree_view_find_node (tree_view, cursor_path,
2694                               &cursor_tree, &cursor);
2695
2696   if (tree_view->priv->drag_dest_row)
2697     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
2698
2699   if (drag_dest_path)
2700     _gtk_tree_view_find_node (tree_view, drag_dest_path,
2701                               &drag_highlight_tree, &drag_highlight);
2702
2703   gdk_drawable_get_size (tree_view->priv->bin_window,
2704                          &bin_window_width, NULL);
2705
2706   for (last_column = g_list_last (tree_view->priv->columns);
2707        last_column &&
2708          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2709          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2710        last_column = last_column->prev)
2711     ;
2712
2713   /* Actually process the expose event.  To do this, we want to
2714    * start at the first node of the event, and walk the tree in
2715    * order, drawing each successive node.
2716    */
2717
2718   do
2719     {
2720       gboolean parity;
2721
2722       max_height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
2723
2724       x_offset = -event->area.x;
2725       cell_offset = 0;
2726       highlight_x = 0; /* should match x coord of first cell */
2727
2728       background_area.y = y_offset + event->area.y;
2729       background_area.height = max_height;
2730
2731       flags = 0;
2732
2733       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
2734         flags |= GTK_CELL_RENDERER_PRELIT;
2735
2736       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
2737         flags |= GTK_CELL_RENDERER_SELECTED;
2738
2739       parity = _gtk_rbtree_node_find_parity (tree, node);
2740
2741       for (list = tree_view->priv->columns; list; list = list->next)
2742         {
2743           GtkTreeViewColumn *column = list->data;
2744           const gchar *detail = NULL;
2745           GtkStateType state;
2746
2747           if (!column->visible)
2748             continue;
2749
2750           if (cell_offset > event->area.x + event->area.width ||
2751               cell_offset + column->width < event->area.x)
2752             {
2753               cell_offset += column->width;
2754               continue;
2755             }
2756
2757           if (column->show_sort_indicator)
2758             flags |= GTK_CELL_RENDERER_SORTED;
2759           else
2760             flags &= ~GTK_CELL_RENDERER_SORTED;
2761
2762           gtk_tree_view_column_cell_set_cell_data (column,
2763                                                    tree_view->priv->model,
2764                                                    &iter,
2765                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2766                                                    node->children?TRUE:FALSE);
2767
2768
2769           background_area.x = cell_offset;
2770           background_area.width = column->width;
2771
2772           cell_area = background_area;
2773           cell_area.y += vertical_separator / 2;
2774           cell_area.x += horizontal_separator / 2;
2775           cell_area.height -= vertical_separator;
2776           cell_area.width -= horizontal_separator;
2777
2778           /* Select the detail for drawing the cell.  relevant
2779            * factors are parity, sortedness, and whether to
2780            * display rules.
2781            */
2782           if (allow_rules && tree_view->priv->has_rules)
2783             {
2784               if (flags & GTK_CELL_RENDERER_SORTED)
2785                 {
2786                   if (parity)
2787                     detail = "cell_odd_ruled_sorted";
2788                   else
2789                     detail = "cell_even_ruled_sorted";
2790                 }
2791               else
2792                 {
2793                   if (parity)
2794                     detail = "cell_odd_ruled";
2795                   else
2796                     detail = "cell_even_ruled";
2797                 }
2798             }
2799           else
2800             {
2801               if (flags & GTK_CELL_RENDERER_SORTED)
2802                 {
2803                   if (parity)
2804                     detail = "cell_odd_sorted";
2805                   else
2806                     detail = "cell_even_sorted";
2807                 }
2808               else
2809                 {
2810                   if (parity)
2811                     detail = "cell_odd";
2812                   else
2813                     detail = "cell_even";
2814                 }
2815             }
2816
2817           g_assert (detail);
2818
2819           if (flags & GTK_CELL_RENDERER_SELECTED)
2820             state = GTK_STATE_SELECTED;
2821           else
2822             state = GTK_STATE_NORMAL;
2823
2824           /* Draw background */
2825           gtk_paint_flat_box (widget->style,
2826                               event->window,
2827                               state,
2828                               GTK_SHADOW_NONE,
2829                               &event->area,
2830                               widget,
2831                               detail,
2832                               background_area.x,
2833                               background_area.y,
2834                               background_area.width,
2835                               background_area.height);
2836
2837           if (gtk_tree_view_is_expander_column (tree_view, column) &&
2838               TREE_VIEW_DRAW_EXPANDERS(tree_view))
2839             {
2840               cell_area.x += depth * tree_view->priv->expander_size;
2841               cell_area.width -= depth * tree_view->priv->expander_size;
2842
2843               /* If we have an expander column, the highlight underline
2844                * starts with that column, so that it indicates which
2845                * level of the tree we're dropping at.
2846                */
2847               highlight_x = cell_area.x;
2848               gtk_tree_view_column_cell_render (column,
2849                                                 event->window,
2850                                                 &background_area,
2851                                                 &cell_area,
2852                                                 &event->area,
2853                                                 flags);
2854               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
2855                 {
2856                   gint x, y;
2857                   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
2858                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2859                                             tree,
2860                                             node,
2861                                             x, y);
2862                 }
2863             }
2864           else
2865             {
2866               gtk_tree_view_column_cell_render (column,
2867                                                 event->window,
2868                                                 &background_area,
2869                                                 &cell_area,
2870                                                 &event->area,
2871                                                 flags);
2872             }
2873           if (node == cursor &&
2874               ((column == tree_view->priv->focus_column &&
2875                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
2876                 GTK_WIDGET_HAS_FOCUS (widget)) ||
2877                (column == tree_view->priv->edited_column)))
2878             {
2879               gtk_tree_view_column_cell_draw_focus (column,
2880                                                     event->window,
2881                                                     &background_area,
2882                                                     &cell_area,
2883                                                     &event->area,
2884                                                     flags);
2885             }
2886           cell_offset += column->width;
2887         }
2888
2889
2890       if (node == drag_highlight)
2891         {
2892           /* Draw indicator for the drop
2893            */
2894           gint highlight_y = -1;
2895           GtkRBTree *tree = NULL;
2896           GtkRBNode *node = NULL;
2897           gint width;
2898           gint focus_line_width;
2899
2900           switch (tree_view->priv->drag_dest_pos)
2901             {
2902             case GTK_TREE_VIEW_DROP_BEFORE:
2903               highlight_y = background_area.y - vertical_separator/2;
2904               break;
2905
2906             case GTK_TREE_VIEW_DROP_AFTER:
2907               highlight_y = background_area.y + background_area.height + vertical_separator/2;
2908               break;
2909
2910             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2911             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2912               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
2913
2914               if (tree == NULL)
2915                 break;
2916               gdk_drawable_get_size (tree_view->priv->bin_window,
2917                                      &width, NULL);
2918               gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
2919               gtk_paint_focus (widget->style,
2920                                tree_view->priv->bin_window,
2921                                GTK_WIDGET_STATE (widget),
2922                                NULL,
2923                                widget,
2924                                "treeview-drop-indicator",
2925                                0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
2926                                - focus_line_width / 2,
2927                                width, MAX(BACKGROUND_HEIGHT (node),
2928                                           tree_view->priv->expander_size)
2929                                - focus_line_width + 1);
2930               break;
2931             }
2932
2933           if (highlight_y >= 0)
2934             {
2935               gdk_draw_line (event->window,
2936                              widget->style->black_gc,
2937                              highlight_x,
2938                              highlight_y,
2939                              bin_window_width - highlight_x,
2940                              highlight_y);
2941             }
2942         }
2943
2944       y_offset += max_height;
2945       if (node->children)
2946         {
2947           GtkTreeIter parent = iter;
2948           gboolean has_child;
2949
2950           tree = node->children;
2951           node = tree->root;
2952
2953           g_assert (node != tree->nil);
2954
2955           while (node->left != tree->nil)
2956             node = node->left;
2957           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
2958                                                     &iter,
2959                                                     &parent);
2960           depth++;
2961
2962           /* Sanity Check! */
2963           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
2964         }
2965       else
2966         {
2967           gboolean done = FALSE;
2968           do
2969             {
2970               node = _gtk_rbtree_next (tree, node);
2971               if (node != NULL)
2972                 {
2973                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
2974                   done = TRUE;
2975
2976                   /* Sanity Check! */
2977                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
2978                 }
2979               else
2980                 {
2981                   GtkTreeIter parent_iter = iter;
2982                   gboolean has_parent;
2983
2984                   node = tree->parent_node;
2985                   tree = tree->parent_tree;
2986                   if (tree == NULL)
2987                     /* we should go to done to free some memory */
2988                     goto done;
2989                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
2990                                                            &iter,
2991                                                            &parent_iter);
2992                   depth--;
2993
2994                   /* Sanity check */
2995                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
2996                 }
2997             }
2998           while (!done);
2999         }
3000     }
3001   while (y_offset < event->area.height);
3002
3003  done:
3004   if (cursor_path)
3005     gtk_tree_path_free (cursor_path);
3006
3007   if (drag_dest_path)
3008     gtk_tree_path_free (drag_dest_path);
3009
3010   return FALSE;
3011 }
3012
3013 static gboolean
3014 gtk_tree_view_expose (GtkWidget      *widget,
3015                       GdkEventExpose *event)
3016 {
3017   GtkTreeView *tree_view;
3018
3019   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3020
3021   tree_view = GTK_TREE_VIEW (widget);
3022
3023   if (event->window == tree_view->priv->bin_window)
3024     return gtk_tree_view_bin_expose (widget, event);
3025   else if (event->window == tree_view->priv->header_window)
3026     {
3027       GList *list;
3028       
3029       for (list = tree_view->priv->columns; list != NULL; list = list->next)
3030         {
3031           GtkTreeViewColumn *column = list->data;
3032
3033           if (column == tree_view->priv->drag_column)
3034             continue;
3035
3036           if (column->visible)
3037             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
3038                                             column->button,
3039                                             event);
3040         }
3041     }
3042   else if (event->window == tree_view->priv->drag_window)
3043     {
3044       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
3045                                       tree_view->priv->drag_column->button,
3046                                       event);
3047     }
3048   return TRUE;
3049 }
3050
3051 static gboolean
3052 gtk_tree_view_key_press (GtkWidget   *widget,
3053                          GdkEventKey *event)
3054 {
3055   GtkTreeView *tree_view = (GtkTreeView *) widget;
3056
3057   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3058     {
3059       if (event->keyval == GDK_Escape)
3060         {
3061           tree_view->priv->cur_reorder = NULL;
3062           gtk_tree_view_button_release_drag_column (widget, NULL);
3063         }
3064       return TRUE;
3065     }
3066
3067   return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
3068 }
3069
3070 /* FIXME Is this function necessary? Can I get an enter_notify event
3071  * w/o either an expose event or a mouse motion event?
3072  */
3073 static gboolean
3074 gtk_tree_view_enter_notify (GtkWidget        *widget,
3075                             GdkEventCrossing *event)
3076 {
3077   GtkTreeView *tree_view;
3078   GtkRBTree *tree;
3079   GtkRBNode *node;
3080   gint new_y;
3081
3082   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3083
3084   tree_view = GTK_TREE_VIEW (widget);
3085
3086   /* Sanity check it */
3087   if (event->window != tree_view->priv->bin_window)
3088     return FALSE;
3089
3090   if (tree_view->priv->tree == NULL)
3091     return FALSE;
3092
3093   if ((tree_view->priv->button_pressed_node != NULL) &&
3094       (tree_view->priv->button_pressed_node != node))
3095     return TRUE;
3096
3097   /* find the node internally */
3098   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
3099   if (new_y < 0)
3100     new_y = 0;
3101   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3102
3103   if (node == NULL)
3104     return FALSE;
3105
3106   do_prelight (tree_view, tree, node, event->x, event->y);
3107
3108   if (tree_view->priv->prelight_node)
3109     _gtk_tree_view_queue_draw_node (tree_view,
3110                                    tree_view->priv->prelight_tree,
3111                                    tree_view->priv->prelight_node,
3112                                    NULL);
3113
3114   return TRUE;
3115 }
3116
3117 static gboolean
3118 gtk_tree_view_leave_notify (GtkWidget        *widget,
3119                             GdkEventCrossing *event)
3120 {
3121   GtkTreeView *tree_view;
3122
3123   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3124
3125   if (event->mode == GDK_CROSSING_GRAB)
3126     return TRUE;
3127   tree_view = GTK_TREE_VIEW (widget);
3128
3129   if (tree_view->priv->prelight_node)
3130     _gtk_tree_view_queue_draw_node (tree_view,
3131                                    tree_view->priv->prelight_tree,
3132                                    tree_view->priv->prelight_node,
3133                                    NULL);
3134
3135   ensure_unprelighted (tree_view);
3136
3137 return TRUE;
3138 }
3139
3140
3141 static gint
3142 gtk_tree_view_focus_in (GtkWidget     *widget,
3143                         GdkEventFocus *event)
3144 {
3145   GtkTreeView *tree_view;
3146
3147   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3148   g_return_val_if_fail (event != NULL, FALSE);
3149
3150   tree_view = GTK_TREE_VIEW (widget);
3151
3152   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3153
3154   gtk_widget_queue_draw (widget);
3155
3156   return FALSE;
3157 }
3158
3159
3160 static gint
3161 gtk_tree_view_focus_out (GtkWidget     *widget,
3162                          GdkEventFocus *event)
3163 {
3164   GtkWidget   *search_dialog;
3165
3166   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3167   g_return_val_if_fail (event != NULL, FALSE);
3168
3169   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3170
3171   gtk_widget_queue_draw (widget);
3172
3173   /* destroy interactive search dialog */
3174   search_dialog = gtk_object_get_data (GTK_OBJECT (widget),
3175                                        GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
3176   if (search_dialog)
3177     gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget));
3178
3179   return FALSE;
3180 }
3181
3182
3183 /* Incremental Reflow
3184  */
3185
3186 /* Returns TRUE if it updated the size
3187  */
3188 static gboolean
3189 validate_row (GtkTreeView *tree_view,
3190               GtkRBTree   *tree,
3191               GtkRBNode   *node,
3192               GtkTreeIter *iter,
3193               GtkTreePath *path)
3194 {
3195   GtkTreeViewColumn *column;
3196   GList *list;
3197   gint height = 0;
3198   gint horizontal_separator;
3199   gint depth = gtk_tree_path_get_depth (path);
3200   gboolean retval = FALSE;
3201
3202   /* double check the row needs validating */
3203   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
3204       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3205     return FALSE;
3206
3207   gtk_widget_style_get (GTK_WIDGET (tree_view),
3208                         "horizontal_separator", &horizontal_separator,
3209                         NULL);
3210
3211   for (list = tree_view->priv->columns; list; list = list->next)
3212     {
3213       gint tmp_width;
3214       gint tmp_height;
3215
3216       column = list->data;
3217
3218       if (! column->visible)
3219         continue;
3220
3221       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
3222         continue;
3223
3224       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
3225                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3226                                                node->children?TRUE:FALSE);
3227       gtk_tree_view_column_cell_get_size (column,
3228                                           NULL, NULL, NULL,
3229                                           &tmp_width, &tmp_height);
3230       height = MAX (height, tmp_height);
3231       height = MAX (height, tree_view->priv->expander_size);
3232
3233       if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3234         {
3235           tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size);
3236         }
3237       else
3238         tmp_width = tmp_width + horizontal_separator;
3239
3240       if (tmp_width > column->requested_width)
3241         {
3242           retval = TRUE;
3243           column->requested_width = tmp_width;
3244         }
3245     }
3246
3247   if (height != GTK_RBNODE_GET_HEIGHT (node))
3248     {
3249       retval = TRUE;
3250       _gtk_rbtree_node_set_height (tree, node, height);
3251     }
3252   _gtk_rbtree_node_mark_valid (tree, node);
3253
3254   return retval;
3255 }
3256
3257
3258 static void
3259 validate_visible_area (GtkTreeView *tree_view)
3260 {
3261   GtkTreePath *path;
3262   GtkTreeIter iter;
3263   GtkRBTree *tree;
3264   GtkRBNode *node;
3265   gint y, height, offset;
3266   gboolean validated_area = FALSE;
3267   gboolean size_changed = FALSE;
3268   
3269   if (tree_view->priv->tree == NULL)
3270     return;
3271   
3272   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
3273     return;
3274   
3275   height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
3276
3277   y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0);
3278
3279   offset = _gtk_rbtree_find_offset (tree_view->priv->tree, y,
3280                                     &tree, &node);
3281   if (node == NULL)
3282     {
3283       path = gtk_tree_path_new_root ();
3284       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3285     }
3286   else
3287     {
3288       path = _gtk_tree_view_find_path (tree_view, tree, node);
3289       height += offset;
3290     }
3291
3292   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3293   do
3294     {
3295       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3296           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3297         {
3298           validated_area = TRUE;
3299           if (validate_row (tree_view, tree, node, &iter, path))
3300             size_changed = TRUE;
3301         }
3302       height -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
3303
3304       if (node->children)
3305         {
3306           GtkTreeIter parent = iter;
3307           gboolean has_child;
3308
3309           tree = node->children;
3310           node = tree->root;
3311
3312           g_assert (node != tree->nil);
3313
3314           while (node->left != tree->nil)
3315             node = node->left;
3316           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
3317                                                     &iter,
3318                                                     &parent);
3319           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
3320           gtk_tree_path_down (path);
3321         }
3322       else
3323         {
3324           gboolean done = FALSE;
3325           do
3326             {
3327               node = _gtk_rbtree_next (tree, node);
3328               if (node != NULL)
3329                 {
3330                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
3331                   done = TRUE;
3332
3333                   /* Sanity Check! */
3334                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
3335                 }
3336               else
3337                 {
3338                   GtkTreeIter parent_iter = iter;
3339                   gboolean has_parent;
3340
3341                   node = tree->parent_node;
3342                   tree = tree->parent_tree;
3343                   if (tree == NULL)
3344                     break;
3345                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
3346                                                            &iter,
3347                                                            &parent_iter);
3348
3349                   /* Sanity check */
3350                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
3351                 }
3352             }
3353           while (!done);
3354         }
3355     }
3356   while (node && height > 0);
3357
3358   if (size_changed)
3359     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3360   if (validated_area)
3361     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3362   if (path)
3363     gtk_tree_path_free (path);
3364 }
3365
3366 /* Our strategy for finding nodes to validate is a little convoluted.  We find
3367  * the left-most uninvalidated node.  We then try walking right, validating
3368  * nodes.  Once we find a valid node, we repeat the previous process of finding
3369  * the first invalid node.
3370  */
3371
3372 static gboolean
3373 validate_rows_handler (GtkTreeView *tree_view)
3374 {
3375   GtkRBTree *tree = NULL;
3376   GtkRBNode *node = NULL;
3377   gboolean validated_area = FALSE;
3378   gint retval = TRUE;
3379   GtkTreePath *path = NULL;
3380   GtkTreeIter iter;
3381   gint i = 0;
3382   g_assert (tree_view);
3383
3384   GDK_THREADS_ENTER ();
3385
3386   if (tree_view->priv->tree == NULL)
3387     {
3388       tree_view->priv->validate_rows_timer = 0;
3389       return FALSE;
3390     }
3391
3392   do
3393     {
3394
3395       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
3396         {
3397           retval = FALSE;
3398           goto done;
3399         }
3400
3401       if (path != NULL)
3402         {
3403           node = _gtk_rbtree_next (tree, node);
3404           if (node != NULL)
3405             {
3406               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
3407               gtk_tree_path_next (path);
3408             }
3409           else
3410             {
3411               gtk_tree_path_free (path);
3412               path = NULL;
3413             }
3414         }
3415
3416       if (path == NULL)
3417         {
3418           tree = tree_view->priv->tree;
3419           node = tree_view->priv->tree->root;
3420
3421           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
3422
3423           do
3424             {
3425               if (node->left != tree->nil &&
3426                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
3427                 {
3428                   node = node->left;
3429                 }
3430               else if (node->right != tree->nil &&
3431                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
3432                 {
3433                   node = node->right;
3434                 }
3435               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3436                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3437                 {
3438                   break;
3439                 }
3440               else if (node->children != NULL)
3441                 {
3442                   tree = node->children;
3443                   node = tree->root;
3444                 }
3445               else
3446                 /* RBTree corruption!  All bad */
3447                 g_assert_not_reached ();
3448             }
3449           while (TRUE);
3450           path = _gtk_tree_view_find_path (tree_view, tree, node);
3451           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3452         }
3453       validated_area = validate_row (tree_view, tree, node, &iter, path) | validated_area;
3454       i++;
3455     }
3456   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
3457   
3458  done:
3459   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
3460     gtk_tree_view_top_row_to_dy (tree_view);
3461   else
3462     gtk_tree_view_dy_to_top_row (tree_view);
3463
3464   if (path) gtk_tree_path_free (path);
3465   if (validated_area)
3466     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3467   if (! retval)
3468     tree_view->priv->validate_rows_timer = 0;
3469
3470   GDK_THREADS_LEAVE ();
3471
3472   return retval;
3473 }
3474
3475 static gboolean
3476 presize_handler_callback (gpointer data)
3477 {
3478   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3479
3480   GDK_THREADS_ENTER ();
3481
3482   if (tree_view->priv->mark_rows_col_dirty)
3483     {
3484       if (tree_view->priv->tree)
3485         _gtk_rbtree_column_invalid (tree_view->priv->tree);
3486       tree_view->priv->mark_rows_col_dirty = FALSE;
3487     }
3488   validate_visible_area (tree_view);
3489   tree_view->priv->presize_handler_timer = 0;
3490                    
3491   GDK_THREADS_LEAVE ();
3492
3493   return FALSE;
3494 }
3495
3496 static void
3497 install_presize_handler (GtkTreeView *tree_view)
3498 {
3499   if (! GTK_WIDGET_REALIZED (tree_view))
3500     return;
3501
3502   if (! tree_view->priv->presize_handler_timer)
3503     {
3504       tree_view->priv->presize_handler_timer =
3505         g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
3506     }
3507   if (! tree_view->priv->validate_rows_timer)
3508     {
3509       tree_view->priv->validate_rows_timer =
3510         g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
3511     }
3512 }
3513
3514 /* Always call this iff dy is in the visible range.  If the tree is empty, then
3515  * it's set to be NULL, and top_row_dy is 0;
3516  */
3517 static void
3518 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
3519 {
3520   GtkTreePath *path;
3521   GtkRBTree *tree;
3522   GtkRBNode *node;
3523
3524   gtk_tree_row_reference_free (tree_view->priv->top_row);
3525   if (tree_view->priv->tree == NULL)
3526     tree = NULL;
3527   else
3528     tree_view->priv->top_row_dy = _gtk_rbtree_find_offset (tree_view->priv->tree,
3529                                                            tree_view->priv->dy,
3530                                                            &tree, &node);
3531   if (tree == NULL)
3532     {
3533       tree_view->priv->top_row = NULL;
3534       tree_view->priv->top_row_dy = 0;
3535       return;
3536     }
3537       
3538   path = _gtk_tree_view_find_path (tree_view, tree, node);
3539   tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
3540   gtk_tree_path_free (path);
3541 }
3542
3543 static void
3544 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
3545 {
3546   GtkTreePath *path;
3547   GtkRBTree *tree;
3548   GtkRBNode *node;
3549
3550   if (tree_view->priv->top_row)
3551     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
3552   else
3553     path = NULL;
3554
3555   if (!path)
3556     tree = NULL;
3557   else
3558     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3559
3560   if (path)
3561     gtk_tree_path_free (path);
3562
3563   if (tree == NULL)
3564     {
3565       /* keep dy and set new toprow */
3566       gtk_tree_row_reference_free (tree_view->priv->top_row);
3567       tree_view->priv->top_row = NULL;
3568       tree_view->priv->top_row_dy = 0;
3569       gtk_tree_view_dy_to_top_row (tree_view);
3570       return;
3571     }
3572
3573   if (MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size)
3574       < tree_view->priv->top_row_dy)
3575     {
3576       /* new top row */
3577       gtk_tree_view_dy_to_top_row (tree_view);
3578       return;
3579     }
3580
3581   tree_view->priv->dy = _gtk_rbtree_node_find_offset (tree, node);
3582   tree_view->priv->dy += tree_view->priv->top_row_dy;
3583   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3584                             tree_view->priv->dy);
3585   gtk_adjustment_changed (tree_view->priv->vadjustment);
3586 }
3587
3588 void
3589 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
3590 {
3591   tree_view->priv->mark_rows_col_dirty = TRUE;
3592
3593   install_presize_handler (tree_view);
3594 }
3595
3596 /* Drag-and-drop */
3597
3598 static void
3599 set_source_row (GdkDragContext *context,
3600                 GtkTreeModel   *model,
3601                 GtkTreePath    *source_row)
3602 {
3603   g_object_set_data_full (G_OBJECT (context),
3604                           "gtk-tree-view-source-row",
3605                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
3606                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
3607 }
3608
3609 static GtkTreePath*
3610 get_source_row (GdkDragContext *context)
3611 {
3612   GtkTreeRowReference *ref =
3613     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
3614
3615   if (ref)
3616     return gtk_tree_row_reference_get_path (ref);
3617   else
3618     return NULL;
3619 }
3620
3621
3622 static void
3623 set_dest_row (GdkDragContext *context,
3624               GtkTreeModel   *model,
3625               GtkTreePath    *dest_row)
3626 {
3627   g_object_set_data_full (G_OBJECT (context),
3628                           "gtk-tree-view-dest-row",
3629                           dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
3630                           (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
3631 }
3632
3633 static GtkTreePath*
3634 get_dest_row (GdkDragContext *context)
3635 {
3636   GtkTreeRowReference *ref =
3637     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
3638
3639   if (ref)
3640     return gtk_tree_row_reference_get_path (ref);
3641   else
3642     return NULL;
3643 }
3644
3645 /* Get/set whether drag_motion requested the drag data and
3646  * drag_data_received should thus not actually insert the data,
3647  * since the data doesn't result from a drop.
3648  */
3649 static void
3650 set_status_pending (GdkDragContext *context,
3651                     GdkDragAction   suggested_action)
3652 {
3653   g_object_set_data (G_OBJECT (context),
3654                      "gtk-tree-view-status-pending",
3655                      GINT_TO_POINTER (suggested_action));
3656 }
3657
3658 static GdkDragAction
3659 get_status_pending (GdkDragContext *context)
3660 {
3661   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
3662                                              "gtk-tree-view-status-pending"));
3663 }
3664
3665 static TreeViewDragInfo*
3666 get_info (GtkTreeView *tree_view)
3667 {
3668   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
3669 }
3670
3671 static void
3672 clear_source_info (TreeViewDragInfo *di)
3673 {
3674   if (di->source_target_list)
3675     gtk_target_list_unref (di->source_target_list);
3676
3677   di->source_target_list = NULL;
3678 }
3679
3680 static void
3681 clear_dest_info (TreeViewDragInfo *di)
3682 {
3683   if (di->dest_target_list)
3684     gtk_target_list_unref (di->dest_target_list);
3685
3686   di->dest_target_list = NULL;
3687 }
3688
3689 static void
3690 destroy_info (TreeViewDragInfo *di)
3691 {
3692   clear_source_info (di);
3693   clear_dest_info (di);
3694   g_free (di);
3695 }
3696
3697 static TreeViewDragInfo*
3698 ensure_info (GtkTreeView *tree_view)
3699 {
3700   TreeViewDragInfo *di;
3701
3702   di = get_info (tree_view);
3703
3704   if (di == NULL)
3705     {
3706       di = g_new0 (TreeViewDragInfo, 1);
3707
3708       g_object_set_data_full (G_OBJECT (tree_view),
3709                               "gtk-tree-view-drag-info",
3710                               di,
3711                               (GDestroyNotify) destroy_info);
3712     }
3713
3714   return di;
3715 }
3716
3717 static void
3718 remove_info (GtkTreeView *tree_view)
3719 {
3720   g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
3721 }
3722
3723 #if 0
3724 static gint
3725 drag_scan_timeout (gpointer data)
3726 {
3727   GtkTreeView *tree_view;
3728   gint x, y;
3729   GdkModifierType state;
3730   GtkTreePath *path = NULL;
3731   GtkTreeViewColumn *column = NULL;
3732   GdkRectangle visible_rect;
3733
3734   GDK_THREADS_ENTER ();
3735
3736   tree_view = GTK_TREE_VIEW (data);
3737
3738   gdk_window_get_pointer (tree_view->priv->bin_window,
3739                           &x, &y, &state);
3740
3741   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3742
3743   /* See if we are near the edge. */
3744   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
3745       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
3746       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
3747       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
3748     {
3749       gtk_tree_view_get_path_at_pos (tree_view,
3750                                      tree_view->priv->bin_window,
3751                                      x, y,
3752                                      &path,
3753                                      &column,
3754                                      NULL,
3755                                      NULL);
3756
3757       if (path != NULL)
3758         {
3759           gtk_tree_view_scroll_to_cell (tree_view,
3760                                         path,
3761                                         column,
3762                                         TRUE,
3763                                         0.5, 0.5);
3764
3765           gtk_tree_path_free (path);
3766         }
3767     }
3768
3769   GDK_THREADS_LEAVE ();
3770
3771   return TRUE;
3772 }
3773 #endif /* 0 */
3774
3775 static void
3776 remove_scroll_timeout (GtkTreeView *tree_view)
3777 {
3778   if (tree_view->priv->scroll_timeout != 0)
3779     {
3780       gtk_timeout_remove (tree_view->priv->scroll_timeout);
3781       tree_view->priv->scroll_timeout = 0;
3782     }
3783 }
3784 static gboolean
3785 check_model_dnd (GtkTreeModel *model,
3786                  GType         required_iface,
3787                  const gchar  *signal)
3788 {
3789   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
3790     {
3791       g_warning ("You must override the default '%s' handler "
3792                  "on GtkTreeView when using models that don't support "
3793                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
3794                  "is to connect to '%s' and call "
3795                  "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
3796                  "the default handler from running. Look at the source code "
3797                  "for the default handler in gtktreeview.c to get an idea what "
3798                  "your handler should do. (gtktreeview.c is in the GTK source "
3799                  "code.) If you're using GTK from a language other than C, "
3800                  "there may be a more natural way to override default handlers, e.g. via derivation.",
3801                  signal, g_type_name (required_iface), signal);
3802       return FALSE;
3803     }
3804   else
3805     return TRUE;
3806 }
3807
3808 static void
3809 remove_open_timeout (GtkTreeView *tree_view)
3810 {
3811   if (tree_view->priv->open_dest_timeout != 0)
3812     {
3813       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
3814       tree_view->priv->open_dest_timeout = 0;
3815     }
3816 }
3817
3818
3819 static gint
3820 open_row_timeout (gpointer data)
3821 {
3822   GtkTreeView *tree_view = data;
3823   GtkTreePath *dest_path = NULL;
3824   GtkTreeViewDropPosition pos;
3825   gboolean result = FALSE;
3826
3827   GDK_THREADS_ENTER ();
3828
3829   gtk_tree_view_get_drag_dest_row (tree_view,
3830                                    &dest_path,
3831                                    &pos);
3832
3833   if (dest_path &&
3834       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3835        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3836     {
3837       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
3838       tree_view->priv->open_dest_timeout = 0;
3839
3840       gtk_tree_path_free (dest_path);
3841     }
3842   else
3843     {
3844       if (dest_path)
3845         gtk_tree_path_free (dest_path);
3846
3847       result = TRUE;
3848     }
3849
3850   GDK_THREADS_LEAVE ();
3851
3852   return result;
3853 }
3854
3855 static gint
3856 scroll_row_timeout (gpointer data)
3857 {
3858   GtkTreeView *tree_view = data;
3859
3860   GDK_THREADS_ENTER ();
3861
3862   gtk_tree_view_vertical_autoscroll (tree_view);
3863
3864   GDK_THREADS_LEAVE ();
3865
3866   return TRUE;
3867 }
3868
3869 /* Returns TRUE if event should not be propagated to parent widgets */
3870 static gboolean
3871 set_destination_row (GtkTreeView    *tree_view,
3872                      GdkDragContext *context,
3873                      gint            x,
3874                      gint            y,
3875                      GdkDragAction  *suggested_action,
3876                      GdkAtom        *target)
3877 {
3878   GtkTreePath *path = NULL;
3879   GtkTreeViewDropPosition pos;
3880   GtkTreeViewDropPosition old_pos;
3881   TreeViewDragInfo *di;
3882   GtkWidget *widget;
3883   GtkTreePath *old_dest_path = NULL;
3884
3885   *suggested_action = 0;
3886   *target = GDK_NONE;
3887
3888   widget = GTK_WIDGET (tree_view);
3889
3890   di = get_info (tree_view);
3891
3892   if (di == NULL)
3893     {
3894       /* someone unset us as a drag dest, note that if
3895        * we return FALSE drag_leave isn't called
3896        */
3897
3898       gtk_tree_view_set_drag_dest_row (tree_view,
3899                                        NULL,
3900                                        GTK_TREE_VIEW_DROP_BEFORE);
3901
3902       remove_scroll_timeout (GTK_TREE_VIEW (widget));
3903       remove_open_timeout (GTK_TREE_VIEW (widget));
3904
3905       return FALSE; /* no longer a drop site */
3906     }
3907
3908   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
3909   if (*target == GDK_NONE)
3910     {
3911       return FALSE;
3912     }
3913
3914   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
3915                                           x, y,
3916                                           &path,
3917                                           &pos))
3918     {
3919       /* can't drop here */
3920       remove_open_timeout (tree_view);
3921
3922       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3923                                        NULL,
3924                                        GTK_TREE_VIEW_DROP_BEFORE);
3925
3926       /* don't propagate to parent though */
3927       return TRUE;
3928     }
3929
3930   g_assert (path);
3931
3932   /* If we left the current row's "open" zone, unset the timeout for
3933    * opening the row
3934    */
3935   gtk_tree_view_get_drag_dest_row (tree_view,
3936                                    &old_dest_path,
3937                                    &old_pos);
3938
3939   if (old_dest_path &&
3940       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
3941        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3942          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
3943     remove_open_timeout (tree_view);
3944
3945   if (old_dest_path)
3946     gtk_tree_path_free (old_dest_path);
3947
3948   if (TRUE /* FIXME if the location droppable predicate */)
3949     {
3950       GtkWidget *source_widget;
3951
3952       *suggested_action = context->suggested_action;
3953
3954       source_widget = gtk_drag_get_source_widget (context);
3955
3956       if (source_widget == widget)
3957         {
3958           /* Default to MOVE, unless the user has
3959            * pressed ctrl or alt to affect available actions
3960            */
3961           if ((context->actions & GDK_ACTION_MOVE) != 0)
3962             *suggested_action = GDK_ACTION_MOVE;
3963         }
3964
3965       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3966                                        path, pos);
3967     }
3968   else
3969     {
3970       /* can't drop here */
3971       remove_open_timeout (tree_view);
3972
3973       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3974                                        NULL,
3975                                        GTK_TREE_VIEW_DROP_BEFORE);
3976     }
3977
3978   return TRUE;
3979 }
3980 static GtkTreePath*
3981 get_logical_dest_row (GtkTreeView *tree_view)
3982
3983 {
3984   /* adjust path to point to the row the drop goes in front of */
3985   GtkTreePath *path = NULL;
3986   GtkTreeViewDropPosition pos;
3987
3988   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3989
3990   if (path == NULL)
3991     return NULL;
3992
3993   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
3994     ; /* do nothing */
3995   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
3996            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3997     {
3998       /* get first child, drop before it */
3999       gtk_tree_path_down (path);
4000     }
4001   else
4002     {
4003       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
4004       gtk_tree_path_next (path);
4005     }
4006
4007   return path;
4008 }
4009
4010 static gboolean
4011 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
4012                                         GdkEventMotion   *event)
4013 {
4014   GdkDragContext *context;
4015   TreeViewDragInfo *di;
4016   GtkTreePath *path = NULL;
4017   gint button;
4018   gint cell_x, cell_y;
4019   GtkTreeModel *model;
4020   gboolean retval = FALSE;
4021
4022   di = get_info (tree_view);
4023
4024   if (di == NULL)
4025     goto out;
4026
4027   if (tree_view->priv->pressed_button < 0)
4028     goto out;
4029
4030   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
4031                                  tree_view->priv->press_start_x,
4032                                  tree_view->priv->press_start_y,
4033                                  event->x, event->y))
4034     goto out;
4035
4036   model = gtk_tree_view_get_model (tree_view);
4037
4038   if (model == NULL)
4039     goto out;
4040
4041   button = tree_view->priv->pressed_button;
4042   tree_view->priv->pressed_button = -1;
4043
4044   gtk_tree_view_get_path_at_pos (tree_view,
4045                                  tree_view->priv->press_start_x,
4046                                  tree_view->priv->press_start_y,
4047                                  &path,
4048                                  NULL,
4049                                  &cell_x,
4050                                  &cell_y);
4051
4052   if (path == NULL)
4053     goto out;
4054
4055   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
4056       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
4057                                            path))
4058     goto out;
4059
4060   /* FIXME Check whether we're a start button, if not return FALSE and
4061    * free path
4062    */
4063
4064   /* Now we can begin the drag */
4065
4066   retval = TRUE;
4067
4068   context = gtk_drag_begin (GTK_WIDGET (tree_view),
4069                             di->source_target_list,
4070                             di->source_actions,
4071                             button,
4072                             (GdkEvent*)event);
4073
4074   gtk_drag_set_icon_default (context);
4075
4076   {
4077     GdkPixmap *row_pix;
4078
4079     row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
4080                                                   path);
4081
4082     gtk_drag_set_icon_pixmap (context,
4083                               gdk_drawable_get_colormap (row_pix),
4084                               row_pix,
4085                               NULL,
4086                               /* the + 1 is for the black border in the icon */
4087                               tree_view->priv->press_start_x + 1,
4088                               cell_y + 1);
4089
4090     gdk_pixmap_unref (row_pix);
4091   }
4092
4093   set_source_row (context, model, path);
4094
4095  out:
4096   if (path)
4097     gtk_tree_path_free (path);
4098
4099   return retval;
4100 }
4101
4102
4103 static void
4104 gtk_tree_view_drag_begin (GtkWidget      *widget,
4105                           GdkDragContext *context)
4106 {
4107   /* do nothing */
4108 }
4109
4110 static void
4111 gtk_tree_view_drag_end (GtkWidget      *widget,
4112                         GdkDragContext *context)
4113 {
4114   /* do nothing */
4115 }
4116
4117 /* Default signal implementations for the drag signals */
4118 static void
4119 gtk_tree_view_drag_data_get (GtkWidget        *widget,
4120                              GdkDragContext   *context,
4121                              GtkSelectionData *selection_data,
4122                              guint             info,
4123                              guint             time)
4124 {
4125   GtkTreeView *tree_view;
4126   GtkTreeModel *model;
4127   TreeViewDragInfo *di;
4128   GtkTreePath *source_row;
4129
4130   tree_view = GTK_TREE_VIEW (widget);
4131
4132   model = gtk_tree_view_get_model (tree_view);
4133
4134   if (model == NULL)
4135     return;
4136
4137   di = get_info (GTK_TREE_VIEW (widget));
4138
4139   if (di == NULL)
4140     return;
4141
4142   source_row = get_source_row (context);
4143
4144   if (source_row == NULL)
4145     return;
4146
4147   /* We can implement the GTK_TREE_MODEL_ROW target generically for
4148    * any model; for DragSource models there are some other targets
4149    * we also support.
4150    */
4151
4152   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
4153       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
4154                                           source_row,
4155                                           selection_data))
4156     goto done;
4157
4158   /* If drag_data_get does nothing, try providing row data. */
4159   if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
4160     {
4161       gtk_tree_set_row_drag_data (selection_data,
4162                                   model,
4163                                   source_row);
4164     }
4165
4166  done:
4167   gtk_tree_path_free (source_row);
4168 }
4169
4170
4171 static void
4172 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
4173                                 GdkDragContext *context)
4174 {
4175   TreeViewDragInfo *di;
4176   GtkTreeModel *model;
4177   GtkTreeView *tree_view;
4178   GtkTreePath *source_row;
4179
4180   tree_view = GTK_TREE_VIEW (widget);
4181   model = gtk_tree_view_get_model (tree_view);
4182
4183   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
4184     return;
4185
4186   di = get_info (tree_view);
4187
4188   if (di == NULL)
4189     return;
4190
4191   source_row = get_source_row (context);
4192
4193   if (source_row == NULL)
4194     return;
4195
4196   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
4197                                          source_row);
4198
4199   gtk_tree_path_free (source_row);
4200
4201   set_source_row (context, NULL, NULL);
4202 }
4203
4204 static void
4205 gtk_tree_view_drag_leave (GtkWidget      *widget,
4206                           GdkDragContext *context,
4207                           guint             time)
4208 {
4209   TreeViewDragInfo *di;
4210
4211   di = get_info (GTK_TREE_VIEW (widget));
4212
4213   /* unset any highlight row */
4214   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4215                                    NULL,
4216                                    GTK_TREE_VIEW_DROP_BEFORE);
4217
4218   remove_scroll_timeout (GTK_TREE_VIEW (widget));
4219   remove_open_timeout (GTK_TREE_VIEW (widget));
4220 }
4221
4222
4223 static gboolean
4224 gtk_tree_view_drag_motion (GtkWidget        *widget,
4225                            GdkDragContext   *context,
4226                            gint              x,
4227                            gint              y,
4228                            guint             time)
4229 {
4230   GtkTreePath *path = NULL;
4231   GtkTreeViewDropPosition pos;
4232   GtkTreeView *tree_view;
4233   GdkDragAction suggested_action = 0;
4234   GdkAtom target;
4235
4236   tree_view = GTK_TREE_VIEW (widget);
4237
4238   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
4239     return FALSE;
4240
4241   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
4242
4243   if (path == NULL)
4244     {
4245       /* Can't drop here. */
4246       gdk_drag_status (context, 0, time);
4247     }
4248   else
4249     {
4250       if (tree_view->priv->open_dest_timeout == 0 &&
4251           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4252            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
4253         {
4254           tree_view->priv->open_dest_timeout =
4255             gtk_timeout_add (500, open_row_timeout, tree_view);
4256         }
4257       else if (tree_view->priv->scroll_timeout == 0)
4258         {
4259           tree_view->priv->scroll_timeout =
4260             gtk_timeout_add (150, scroll_row_timeout, tree_view);
4261         }
4262
4263       if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
4264         {
4265           /* Request data so we can use the source row when
4266            * determining whether to accept the drop
4267            */
4268           set_status_pending (context, suggested_action);
4269           gtk_drag_get_data (widget, context, target, time);
4270         }
4271       else
4272         {
4273           set_status_pending (context, 0);
4274           gdk_drag_status (context, suggested_action, time);
4275         }
4276     }
4277
4278   if (path)
4279     gtk_tree_path_free (path);
4280
4281   return TRUE;
4282 }
4283
4284
4285 static gboolean
4286 gtk_tree_view_drag_drop (GtkWidget        *widget,
4287                          GdkDragContext   *context,
4288                          gint              x,
4289                          gint              y,
4290                          guint             time)
4291 {
4292   GtkTreeView *tree_view;
4293   GtkTreePath *path;
4294   GdkDragAction suggested_action = 0;
4295   GdkAtom target = GDK_NONE;
4296   TreeViewDragInfo *di;
4297   GtkTreeModel *model;
4298
4299   tree_view = GTK_TREE_VIEW (widget);
4300
4301   model = gtk_tree_view_get_model (tree_view);
4302
4303   remove_scroll_timeout (GTK_TREE_VIEW (widget));
4304   remove_open_timeout (GTK_TREE_VIEW (widget));
4305
4306   di = get_info (tree_view);
4307
4308   if (di == NULL)
4309     return FALSE;
4310
4311   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
4312     return FALSE;
4313
4314   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
4315     return FALSE;
4316
4317   path = get_logical_dest_row (tree_view);
4318
4319   if (target != GDK_NONE && path != NULL)
4320     {
4321       /* in case a motion had requested drag data, change things so we
4322        * treat drag data receives as a drop.
4323        */
4324       set_status_pending (context, 0);
4325
4326       set_dest_row (context, model, path);
4327     }
4328
4329   if (path)
4330     gtk_tree_path_free (path);
4331
4332   /* Unset this thing */
4333   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4334                                    NULL,
4335                                    GTK_TREE_VIEW_DROP_BEFORE);
4336
4337   if (target != GDK_NONE)
4338     {
4339       gtk_drag_get_data (widget, context, target, time);
4340       return TRUE;
4341     }
4342   else
4343     return FALSE;
4344 }
4345
4346 static void
4347 gtk_tree_view_drag_data_received (GtkWidget        *widget,
4348                                   GdkDragContext   *context,
4349                                   gint              x,
4350                                   gint              y,
4351                                   GtkSelectionData *selection_data,
4352                                   guint             info,
4353                                   guint             time)
4354 {
4355   GtkTreePath *path;
4356   TreeViewDragInfo *di;
4357   gboolean accepted = FALSE;
4358   GtkTreeModel *model;
4359   GtkTreeView *tree_view;
4360   GtkTreePath *dest_row;
4361   GdkDragAction suggested_action;
4362
4363   tree_view = GTK_TREE_VIEW (widget);
4364
4365   model = gtk_tree_view_get_model (tree_view);
4366
4367   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
4368     return;
4369
4370   di = get_info (tree_view);
4371
4372   if (di == NULL)
4373     return;
4374
4375   suggested_action = get_status_pending (context);
4376
4377   if (suggested_action)
4378     {
4379       /* We are getting this data due to a request in drag_motion,
4380        * rather than due to a request in drag_drop, so we are just
4381        * supposed to call drag_status, not actually paste in the
4382        * data.
4383        */
4384       path = get_logical_dest_row (tree_view);
4385
4386       if (path == NULL)
4387         suggested_action = 0;
4388
4389       if (suggested_action)
4390         {
4391           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
4392                                                      path,
4393                                                      selection_data))
4394             suggested_action = 0;
4395         }
4396
4397       gdk_drag_status (context, suggested_action, time);
4398
4399       if (path)
4400         gtk_tree_path_free (path);
4401
4402       /* If you can't drop, remove user drop indicator until the next motion */
4403       if (suggested_action == 0)
4404         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4405                                          NULL,
4406                                          GTK_TREE_VIEW_DROP_BEFORE);
4407
4408       return;
4409     }
4410
4411   dest_row = get_dest_row (context);
4412
4413   if (dest_row == NULL)
4414     return;
4415
4416   if (selection_data->length >= 0)
4417     {
4418       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
4419                                                  dest_row,
4420                                                  selection_data))
4421         accepted = TRUE;
4422     }
4423
4424   gtk_drag_finish (context,
4425                    accepted,
4426                    (context->action == GDK_ACTION_MOVE),
4427                    time);
4428
4429   gtk_tree_path_free (dest_row);
4430
4431   /* drop dest_row */
4432   set_dest_row (context, NULL, NULL);
4433 }
4434
4435
4436
4437 /* GtkContainer Methods
4438  */
4439
4440
4441 static void
4442 gtk_tree_view_remove (GtkContainer *container,
4443                       GtkWidget    *widget)
4444 {
4445   GtkTreeView *tree_view;
4446   GtkTreeViewChild *child = NULL;
4447   GList *tmp_list;
4448
4449   g_return_if_fail (GTK_IS_TREE_VIEW (container));
4450
4451   tree_view = GTK_TREE_VIEW (container);
4452
4453   tmp_list = tree_view->priv->children;
4454   while (tmp_list)
4455     {
4456       child = tmp_list->data;
4457       if (child->widget == widget)
4458         {
4459           gtk_widget_unparent (widget);
4460
4461           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
4462           g_list_free_1 (tmp_list);
4463           g_free (child);
4464           return;
4465         }
4466
4467       tmp_list = tmp_list->next;
4468     }
4469
4470   tmp_list = tree_view->priv->columns;
4471
4472   while (tmp_list)
4473     {
4474       GtkTreeViewColumn *column;
4475       column = tmp_list->data;
4476       if (column->button == widget)
4477         {
4478           gtk_widget_unparent (widget);
4479           return;
4480         }
4481       tmp_list = tmp_list->next;
4482     }
4483 }
4484
4485 static void
4486 gtk_tree_view_forall (GtkContainer *container,
4487                       gboolean      include_internals,
4488                       GtkCallback   callback,
4489                       gpointer      callback_data)
4490 {
4491   GtkTreeView *tree_view;
4492   GtkTreeViewChild *child = NULL;
4493   GtkTreeViewColumn *column;
4494   GList *tmp_list;
4495
4496   g_return_if_fail (GTK_IS_TREE_VIEW (container));
4497   g_return_if_fail (callback != NULL);
4498
4499   tree_view = GTK_TREE_VIEW (container);
4500
4501   tmp_list = tree_view->priv->children;
4502   while (tmp_list)
4503     {
4504       child = tmp_list->data;
4505       tmp_list = tmp_list->next;
4506
4507       (* callback) (child->widget, callback_data);
4508     }
4509   if (include_internals == FALSE)
4510     return;
4511
4512   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
4513     {
4514       column = tmp_list->data;
4515
4516       if (column->button)
4517         (* callback) (column->button, callback_data);
4518     }
4519 }
4520
4521 /* Returns TRUE if the focus is within the headers, after the focus operation is
4522  * done
4523  */
4524 static gboolean
4525 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
4526                             GtkDirectionType  dir)
4527 {
4528   GtkWidget *focus_child;
4529   GtkContainer *container;
4530
4531   GList *last_column, *first_column;
4532   GList *tmp_list;
4533
4534   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
4535     return FALSE;
4536
4537   focus_child = GTK_CONTAINER (tree_view)->focus_child;
4538   container = GTK_CONTAINER (tree_view);
4539
4540   last_column = g_list_last (tree_view->priv->columns);
4541   while (last_column)
4542     {
4543       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
4544           GTK_TREE_VIEW_COLUMN (last_column->data)->clickable &&
4545           GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable &&
4546           GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
4547         break;
4548       last_column = last_column->prev;
4549     }
4550
4551   /* No headers are visible, or are focusable.  We can't focus in or out.
4552    */
4553   if (last_column == NULL)
4554     return FALSE;
4555
4556   first_column = tree_view->priv->columns;
4557   while (first_column)
4558     {
4559       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
4560           GTK_TREE_VIEW_COLUMN (first_column->data)->clickable &&
4561           GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable &&
4562           GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
4563         break;
4564       first_column = first_column->next;
4565     }
4566
4567   switch (dir)
4568     {
4569     case GTK_DIR_TAB_BACKWARD:
4570     case GTK_DIR_TAB_FORWARD:
4571     case GTK_DIR_UP:
4572     case GTK_DIR_DOWN:
4573       if (focus_child == NULL)
4574         {
4575           if (tree_view->priv->focus_column != NULL)
4576             focus_child = tree_view->priv->focus_column->button;
4577           else
4578             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
4579           gtk_widget_grab_focus (focus_child);
4580           break;
4581         }
4582       return FALSE;
4583
4584     case GTK_DIR_LEFT:
4585     case GTK_DIR_RIGHT:
4586       if (focus_child == NULL)
4587         {
4588           if (tree_view->priv->focus_column != NULL)
4589             focus_child = tree_view->priv->focus_column->button;
4590           else if (dir == GTK_DIR_LEFT)
4591             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
4592           else
4593             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
4594           gtk_widget_grab_focus (focus_child);
4595           break;
4596         }
4597
4598       if (gtk_widget_child_focus (focus_child, dir))
4599         {
4600           /* The focus moves inside the button. */
4601           /* This is probably a great example of bad UI */
4602           break;
4603         }
4604
4605       /* We need to move the focus among the row of buttons. */
4606       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
4607         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
4608           break;
4609
4610       if (tmp_list == first_column && dir == GTK_DIR_LEFT)
4611         {
4612           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
4613           gtk_widget_grab_focus (focus_child);
4614           break;
4615         }
4616       else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
4617         {
4618           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
4619           gtk_widget_grab_focus (focus_child);
4620           break;
4621         }
4622
4623       while (tmp_list)
4624         {
4625           GtkTreeViewColumn *column;
4626
4627           if (dir == GTK_DIR_RIGHT)
4628             tmp_list = tmp_list->next;
4629           else
4630             tmp_list = tmp_list->prev;
4631
4632           if (tmp_list == NULL)
4633             {
4634               g_warning ("Internal button not found");
4635               break;
4636             }
4637           column = tmp_list->data;
4638           if (column->button &&
4639               column->visible &&
4640               GTK_WIDGET_CAN_FOCUS (column->button))
4641             {
4642               focus_child = column->button;
4643               gtk_widget_grab_focus (column->button);
4644               break;
4645             }
4646         }
4647       break;
4648     default:
4649       g_assert_not_reached ();
4650       break;
4651     }
4652
4653   /* if focus child is non-null, we assume it's been set to the current focus child
4654    */
4655   if (focus_child)
4656     {
4657       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
4658         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
4659           break;
4660
4661       tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
4662
4663       /* If the following isn't true, then the view is smaller then the scrollpane.
4664        */
4665       if ((focus_child->allocation.x + focus_child->allocation.width) <=
4666           (tree_view->priv->hadjustment->upper))
4667         {
4668           /* Scroll to the button, if needed */
4669           if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
4670               (focus_child->allocation.x + focus_child->allocation.width))
4671             gtk_adjustment_set_value (tree_view->priv->hadjustment,
4672                                       focus_child->allocation.x + focus_child->allocation.width -
4673                                       tree_view->priv->hadjustment->page_size);
4674           else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
4675             gtk_adjustment_set_value (tree_view->priv->hadjustment,
4676                                       focus_child->allocation.x);
4677         }
4678     }
4679
4680   return (focus_child != NULL);
4681 }
4682
4683 static gint
4684 gtk_tree_view_focus (GtkWidget        *widget,
4685                      GtkDirectionType  direction)
4686 {
4687   GtkTreeView *tree_view;
4688   GtkWidget *focus_child;
4689   GtkContainer *container;
4690
4691   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
4692   g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
4693
4694   container = GTK_CONTAINER (widget);
4695   tree_view = GTK_TREE_VIEW (widget);
4696
4697   if (!GTK_WIDGET_IS_SENSITIVE (container))
4698     return FALSE;
4699
4700   focus_child = container->focus_child;
4701
4702   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
4703   /* Case 1.  Headers currently have focus. */
4704   if (focus_child)
4705     {
4706       switch (direction)
4707         {
4708         case GTK_DIR_LEFT:
4709         case GTK_DIR_RIGHT:
4710           gtk_tree_view_header_focus (tree_view, direction);
4711           return TRUE;
4712         case GTK_DIR_TAB_BACKWARD:
4713         case GTK_DIR_UP:
4714           return FALSE;
4715         case GTK_DIR_TAB_FORWARD:
4716         case GTK_DIR_DOWN:
4717           if (tree_view->priv->tree == NULL)
4718             return FALSE;
4719           gtk_tree_view_focus_to_cursor (tree_view);
4720           return TRUE;
4721         }
4722     }
4723
4724   /* Case 2. We don't have focus at all. */
4725   if (!GTK_WIDGET_HAS_FOCUS (container))
4726     {
4727       if (tree_view->priv->tree == NULL &&
4728           (direction == GTK_DIR_TAB_BACKWARD ||
4729            direction == GTK_DIR_UP))
4730         return gtk_tree_view_header_focus (tree_view, direction);
4731       if (((direction == GTK_DIR_TAB_FORWARD) ||
4732            (direction == GTK_DIR_RIGHT) ||
4733            (direction == GTK_DIR_DOWN) ||
4734            (direction == GTK_DIR_LEFT)) &&
4735           gtk_tree_view_header_focus (tree_view, direction))
4736         return TRUE;
4737
4738       if (tree_view->priv->tree == NULL)
4739         return FALSE;
4740       gtk_tree_view_focus_to_cursor (tree_view);
4741       return TRUE;
4742     }
4743
4744   /* Case 3. We have focus already. */
4745   if (tree_view->priv->tree == NULL)
4746     return gtk_tree_view_header_focus (tree_view, direction);
4747
4748   if (direction == GTK_DIR_TAB_BACKWARD)
4749     return (gtk_tree_view_header_focus (tree_view, direction));
4750   else if (direction == GTK_DIR_TAB_FORWARD)
4751     return FALSE;
4752
4753   /* Other directions caught by the keybindings */
4754   gtk_tree_view_focus_to_cursor (tree_view);
4755   return TRUE;
4756 }
4757
4758 static void
4759 gtk_tree_view_style_set (GtkWidget *widget,
4760                          GtkStyle *previous_style)
4761 {
4762   GtkTreeView *tree_view;
4763   GList *list;
4764   GtkTreeViewColumn *column;
4765
4766   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
4767
4768   tree_view = GTK_TREE_VIEW (widget);
4769
4770   gtk_widget_style_get (widget,
4771                         "expander_size", &tree_view->priv->expander_size,
4772                         NULL);
4773   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
4774
4775   for (list = tree_view->priv->columns; list; list = list->next)
4776     {
4777       column = list->data;
4778       gtk_tree_view_column_cell_set_dirty (column);
4779     }
4780
4781   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
4782
4783   gtk_widget_queue_resize (widget);
4784 }
4785
4786
4787 static void
4788 gtk_tree_view_set_focus_child (GtkContainer *container,
4789                                GtkWidget    *child)
4790 {
4791   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
4792   GList *list;
4793
4794   for (list = tree_view->priv->columns; list; list = list->next)
4795     {
4796       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
4797         {
4798           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
4799           break;
4800         }
4801     }
4802
4803   (* parent_class->set_focus_child) (container, child);
4804 }
4805
4806 static void
4807 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
4808                                GtkAdjustment *hadj,
4809                                GtkAdjustment *vadj)
4810 {
4811   gboolean need_adjust = FALSE;
4812
4813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4814
4815   if (hadj)
4816     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4817   else
4818     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4819   if (vadj)
4820     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4821   else
4822     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4823
4824   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4825     {
4826       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4827       gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4828     }
4829
4830   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4831     {
4832       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4833       gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4834     }
4835
4836   if (tree_view->priv->hadjustment != hadj)
4837     {
4838       tree_view->priv->hadjustment = hadj;
4839       gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4840       gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4841
4842       gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4843                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4844                           tree_view);
4845       need_adjust = TRUE;
4846     }
4847
4848   if (tree_view->priv->vadjustment != vadj)
4849     {
4850       tree_view->priv->vadjustment = vadj;
4851       gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4852       gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4853
4854       gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4855                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4856                           tree_view);
4857       need_adjust = TRUE;
4858     }
4859
4860   if (need_adjust)
4861     gtk_tree_view_adjustment_changed (NULL, tree_view);
4862 }
4863
4864
4865 static void
4866 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
4867                                 GtkMovementStep    step,
4868                                 gint               count)
4869 {
4870   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4871   g_return_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
4872                     step == GTK_MOVEMENT_VISUAL_POSITIONS ||
4873                     step == GTK_MOVEMENT_DISPLAY_LINES ||
4874                     step == GTK_MOVEMENT_PAGES ||
4875                     step == GTK_MOVEMENT_BUFFER_ENDS);
4876
4877   if (tree_view->priv->tree == NULL)
4878     return;
4879   gtk_tree_view_stop_editing (tree_view, FALSE);
4880   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
4881   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
4882
4883   switch (step)
4884     {
4885       /* currently we make no distinction.  When we go bi-di, we need to */
4886     case GTK_MOVEMENT_LOGICAL_POSITIONS:
4887     case GTK_MOVEMENT_VISUAL_POSITIONS:
4888       gtk_tree_view_move_cursor_left_right (tree_view, count);
4889       break;
4890     case GTK_MOVEMENT_DISPLAY_LINES:
4891       gtk_tree_view_move_cursor_up_down (tree_view, count);
4892       break;
4893     case GTK_MOVEMENT_PAGES:
4894       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
4895       break;
4896     case GTK_MOVEMENT_BUFFER_ENDS:
4897       gtk_tree_view_move_cursor_start_end (tree_view, count);
4898       break;
4899     default:
4900       g_assert_not_reached ();
4901     }
4902 }
4903
4904 static void
4905 gtk_tree_view_put (GtkTreeView *tree_view,
4906                    GtkWidget   *child_widget,
4907                    gint         x,
4908                    gint         y,
4909                    gint         width,
4910                    gint         height)
4911 {
4912   GtkTreeViewChild *child;
4913
4914   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4915   g_return_if_fail (GTK_IS_WIDGET (child_widget));
4916
4917   child = g_new (GtkTreeViewChild, 1);
4918
4919   child->widget = child_widget;
4920   child->x = x;
4921   child->y = y;
4922   child->width = width;
4923   child->height = height;
4924
4925   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
4926
4927   if (GTK_WIDGET_REALIZED (tree_view))
4928     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
4929
4930   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
4931 }
4932
4933 void
4934 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
4935                                   GtkWidget   *widget,
4936                                   gint         x,
4937                                   gint         y,
4938                                   gint         width,
4939                                   gint         height)
4940 {
4941   GtkTreeViewChild *child = NULL;
4942   GList *list;
4943   GdkRectangle allocation;
4944
4945   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4946   g_return_if_fail (GTK_IS_WIDGET (widget));
4947
4948   for (list = tree_view->priv->children; list; list = list->next)
4949     {
4950       if (((GtkTreeViewChild *)list->data)->widget == widget)
4951         {
4952           child = list->data;
4953           break;
4954         }
4955     }
4956   if (child == NULL)
4957     return;
4958
4959   allocation.x = child->x = x;
4960   allocation.y = child->y = y;
4961   allocation.width = child->width = width;
4962   allocation.height = child->height = height;
4963
4964   if (GTK_WIDGET_REALIZED (widget))
4965     gtk_widget_size_allocate (widget, &allocation);
4966 }
4967
4968
4969 /* TreeModel Callbacks
4970  */
4971
4972 static void
4973 gtk_tree_view_row_changed (GtkTreeModel *model,
4974                            GtkTreePath  *path,
4975                            GtkTreeIter  *iter,
4976                            gpointer      data)
4977 {
4978   GtkTreeView *tree_view = (GtkTreeView *)data;
4979   GtkRBTree *tree;
4980   GtkRBNode *node;
4981   gboolean free_path = FALSE;
4982   gint vertical_separator;
4983   GList *list;
4984
4985   g_return_if_fail (path != NULL || iter != NULL);
4986
4987   if (!GTK_WIDGET_REALIZED (tree_view))
4988     /* We can just ignore ::changed signals if we aren't realized, as we don't care about sizes
4989      */
4990     return;
4991
4992   gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
4993
4994   if (path == NULL)
4995     {
4996       path = gtk_tree_model_get_path (model, iter);
4997       free_path = TRUE;
4998     }
4999   else if (iter == NULL)
5000     gtk_tree_model_get_iter (model, iter, path);
5001
5002   if (_gtk_tree_view_find_node (tree_view,
5003                                 path,
5004                                 &tree,
5005                                 &node))
5006     /* We aren't actually showing the node */
5007     goto done;
5008
5009   if (tree == NULL)
5010     goto done;
5011
5012   _gtk_rbtree_node_mark_invalid (tree, node);
5013   for (list = tree_view->priv->columns; list; list = list->next)
5014     {
5015       GtkTreeViewColumn *column;
5016
5017       column = list->data;
5018       if (! column->visible)
5019         continue;
5020
5021       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5022         {
5023           gtk_tree_view_column_cell_set_dirty (column);
5024         }
5025     }
5026
5027  done:
5028   install_presize_handler (tree_view);
5029   if (free_path)
5030     gtk_tree_path_free (path);
5031 }
5032
5033 static void
5034 gtk_tree_view_row_inserted (GtkTreeModel *model,
5035                             GtkTreePath  *path,
5036                             GtkTreeIter  *iter,
5037                             gpointer      data)
5038 {
5039   GtkTreeView *tree_view = (GtkTreeView *) data;
5040   gint *indices;
5041   GtkRBTree *tmptree, *tree;
5042   GtkRBNode *tmpnode = NULL;
5043   gint depth;
5044   gint i = 0;
5045   gboolean free_path = FALSE;
5046
5047   g_return_if_fail (path != NULL || iter != NULL);
5048
5049   if (path == NULL)
5050     {
5051       path = gtk_tree_model_get_path (model, iter);
5052       free_path = TRUE;
5053     }
5054   else if (iter == NULL)
5055     gtk_tree_model_get_iter (model, iter, path);
5056
5057   if (tree_view->priv->tree == NULL)
5058     tree_view->priv->tree = _gtk_rbtree_new ();
5059
5060   tmptree = tree = tree_view->priv->tree;
5061
5062   /* Update all row-references */
5063   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
5064   depth = gtk_tree_path_get_depth (path);
5065   indices = gtk_tree_path_get_indices (path);
5066
5067   /* First, find the parent tree */
5068   while (i < depth - 1)
5069     {
5070       if (tmptree == NULL)
5071         {
5072           /* We aren't showing the node */
5073           goto done;
5074         }
5075
5076       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5077       if (tmpnode == NULL)
5078         {
5079           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
5080                      "This possibly means that a GtkTreeModel inserted a child node\n" \
5081                      "before the parent was inserted.");
5082           goto done;
5083         }
5084       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
5085         {
5086           /* FIXME enforce correct behavior on model, probably */
5087           /* In theory, the model should have emitted has_child_toggled here.  We
5088            * try to catch it anyway, just to be safe, in case the model hasn't.
5089            */
5090           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
5091                                                            tree,
5092                                                            tmpnode);
5093           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
5094           gtk_tree_path_free (tmppath);
5095           goto done;
5096         }
5097
5098       tmptree = tmpnode->children;
5099       tree = tmptree;
5100       i++;
5101     }
5102
5103   if (tree == NULL)
5104     goto done;
5105
5106   /* ref the node */
5107   gtk_tree_model_ref_node (tree_view->priv->model, iter);
5108   if (indices[depth - 1] == 0)
5109     {
5110       tmpnode = _gtk_rbtree_find_count (tree, 1);
5111       _gtk_rbtree_insert_before (tree, tmpnode, 0, FALSE);
5112     }
5113   else
5114     {
5115       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
5116       _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE);
5117     }
5118
5119  done:
5120   install_presize_handler (tree_view);
5121   if (free_path)
5122     gtk_tree_path_free (path);
5123 }
5124
5125 static void
5126 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
5127                                      GtkTreePath  *path,
5128                                      GtkTreeIter  *iter,
5129                                      gpointer      data)
5130 {
5131   GtkTreeView *tree_view = (GtkTreeView *)data;
5132   GtkTreeIter real_iter;
5133   gboolean has_child;
5134   GtkRBTree *tree;
5135   GtkRBNode *node;
5136   gboolean free_path = FALSE;
5137
5138   g_return_if_fail (path != NULL || iter != NULL);
5139
5140   if (iter)
5141     real_iter = *iter;
5142
5143   if (path == NULL)
5144     {
5145       path = gtk_tree_model_get_path (model, iter);
5146       free_path = TRUE;
5147     }
5148   else if (iter == NULL)
5149     gtk_tree_model_get_iter (model, &real_iter, path);
5150
5151   if (_gtk_tree_view_find_node (tree_view,
5152                                 path,
5153                                 &tree,
5154                                 &node))
5155     /* We aren't actually showing the node */
5156     goto done;
5157
5158   if (tree == NULL)
5159     goto done;
5160
5161   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
5162   /* Sanity check.
5163    */
5164   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
5165     goto done;
5166
5167   if (has_child)
5168     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
5169   else
5170     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
5171
5172   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
5173     {
5174       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
5175       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
5176         {
5177           GList *list;
5178
5179           for (list = tree_view->priv->columns; list; list = list->next)
5180             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
5181               {
5182                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
5183                 gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data));
5184                 break;
5185               }
5186         }
5187       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5188     }
5189   else
5190     {
5191       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5192     }
5193
5194  done:
5195   if (free_path)
5196     gtk_tree_path_free (path);
5197 }
5198
5199 static void
5200 count_children_helper (GtkRBTree *tree,
5201                        GtkRBNode *node,
5202                        gpointer   data)
5203 {
5204   if (node->children)
5205     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
5206   (*((gint *)data))++;
5207 }
5208
5209 static void
5210 gtk_tree_view_row_deleted (GtkTreeModel *model,
5211                            GtkTreePath  *path,
5212                            gpointer      data)
5213 {
5214   GtkTreeView *tree_view = (GtkTreeView *)data;
5215   GtkRBTree *tree;
5216   GtkRBNode *node;
5217   GList *list;
5218   gint selection_changed;
5219
5220   g_return_if_fail (path != NULL);
5221
5222   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
5223
5224   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5225     return;
5226
5227   if (tree == NULL)
5228     return;
5229
5230   /* Change the selection */
5231   selection_changed = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
5232
5233   for (list = tree_view->priv->columns; list; list = list->next)
5234     if (((GtkTreeViewColumn *)list->data)->visible &&
5235         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5236       gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data);
5237
5238   /* Ensure we don't have a dangling pointer to a dead node */
5239   ensure_unprelighted (tree_view);
5240
5241   /* Cancel editting if we've started */
5242   gtk_tree_view_stop_editing (tree_view, TRUE);
5243
5244   /* If we have a node expanded/collapsed timeout, remove it */
5245   if (tree_view->priv->expand_collapse_timeout != 0)
5246     {
5247       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
5248       tree_view->priv->expand_collapse_timeout = 0;
5249
5250       /* Reset node */
5251       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
5252       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
5253       tree_view->priv->expanded_collapsed_node = NULL;
5254     }
5255
5256   if (tree_view->priv->destroy_count_func)
5257     {
5258       gint child_count = 0;
5259       if (node->children)
5260         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
5261       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
5262     }
5263
5264   if (tree->root->count == 1)
5265     {
5266       if (tree_view->priv->tree == tree)
5267         tree_view->priv->tree = NULL;
5268
5269       _gtk_rbtree_remove (tree);
5270     }
5271   else
5272     {
5273       _gtk_rbtree_remove_node (tree, node);
5274     }
5275
5276   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
5277     gtk_tree_view_top_row_to_dy (tree_view);
5278   else
5279     gtk_tree_view_dy_to_top_row (tree_view);
5280
5281   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5282
5283   if (selection_changed)
5284     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
5285 }
5286
5287
5288 static void
5289 gtk_tree_view_rows_reordered (GtkTreeModel *model,
5290                               GtkTreePath  *parent,
5291                               GtkTreeIter  *iter,
5292                               gint         *new_order,
5293                               gpointer      data)
5294 {
5295   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
5296   GtkRBTree *tree;
5297   GtkRBNode *node;
5298   gint len;
5299
5300   len = gtk_tree_model_iter_n_children (model, iter);
5301
5302   if (len < 2)
5303     return;
5304
5305   gtk_tree_row_reference_reordered (G_OBJECT (data),
5306                                     parent,
5307                                     iter,
5308                                     new_order);
5309
5310   if (_gtk_tree_view_find_node (tree_view,
5311                                 parent,
5312                                 &tree,
5313                                 &node))
5314     return;
5315
5316   /* We need to special case the parent path */
5317   if (tree == NULL)
5318     tree = tree_view->priv->tree;
5319   else
5320     tree = node->children;
5321
5322   if (tree == NULL)
5323     return;
5324
5325   /* we need to be unprelighted */
5326   ensure_unprelighted (tree_view);
5327   
5328   _gtk_rbtree_reorder (tree, new_order, len);
5329
5330   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5331
5332   gtk_tree_view_dy_to_top_row (tree_view);
5333 }
5334
5335
5336 /* Internal tree functions
5337  */
5338
5339
5340 static void
5341 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
5342                                      GtkRBTree         *tree,
5343                                      GtkTreeViewColumn *column,
5344                                      gint              *x1,
5345                                      gint              *x2)
5346 {
5347   GtkTreeViewColumn *tmp_column = NULL;
5348   gint total_width;
5349   GList *list;
5350
5351   if (x1)
5352     *x1 = 0;
5353
5354   if (x2)
5355     *x2 = 0;
5356
5357   total_width = 0;
5358   for (list = tree_view->priv->columns; list; list = list->next)
5359     {
5360       tmp_column = list->data;
5361
5362       if (tmp_column == column)
5363         break;
5364
5365       if (tmp_column->visible)
5366         total_width += tmp_column->width;
5367     }
5368
5369   if (tmp_column != column)
5370     {
5371       g_warning (G_STRLOC": passed-in column isn't in the tree");
5372       return;
5373     }
5374
5375   if (x1)
5376     *x1 = total_width;
5377
5378   if (x2)
5379     {
5380       if (column->visible)
5381         *x2 = total_width + column->width;
5382       else
5383         *x2 = total_width; /* width of 0 */
5384     }
5385 }
5386 static void
5387 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
5388                                 GtkRBTree   *tree,
5389                                 gint        *x1,
5390                                 gint        *x2)
5391 {
5392   gint x_offset = 0;
5393   GList *list;
5394   GtkTreeViewColumn *tmp_column = NULL;
5395   gint total_width;
5396   gboolean indent_expanders;
5397
5398   total_width = 0;
5399   for (list = tree_view->priv->columns; list; list = list->next)
5400     {
5401       tmp_column = list->data;
5402
5403       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
5404         {
5405           x_offset = total_width;
5406           break;
5407         }
5408
5409       if (tmp_column->visible)
5410         total_width += tmp_column->width;
5411     }
5412
5413   gtk_widget_style_get (GTK_WIDGET (tree_view),
5414                         "indent_expanders", &indent_expanders,
5415                         NULL);
5416
5417   if (indent_expanders)
5418     x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
5419
5420   if (x1)
5421     *x1 = x_offset;
5422
5423   if (tmp_column && tmp_column->visible)
5424     {
5425       /* +1 because x2 isn't included in the range. */
5426       if (x2)
5427         *x2 = x_offset + tree_view->priv->expander_size + 1;
5428     }
5429   else
5430     {
5431       /* return an empty range, the expander column is hidden */
5432       if (x2)
5433         *x2 = x_offset;
5434     }
5435 }
5436
5437 static void
5438 gtk_tree_view_build_tree (GtkTreeView *tree_view,
5439                           GtkRBTree   *tree,
5440                           GtkTreeIter *iter,
5441                           gint         depth,
5442                           gboolean     recurse)
5443 {
5444   GtkRBNode *temp = NULL;
5445
5446   do
5447     {
5448       gtk_tree_model_ref_node (tree_view->priv->model, iter);
5449       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
5450       if (recurse)
5451         {
5452           GtkTreeIter child;
5453
5454           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
5455             {
5456               temp->children = _gtk_rbtree_new ();
5457               temp->children->parent_tree = tree;
5458               temp->children->parent_node = temp;
5459               gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
5460             }
5461         }
5462       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
5463         {
5464           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
5465             temp->flags ^= GTK_RBNODE_IS_PARENT;
5466           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
5467         }
5468     }
5469   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
5470 }
5471
5472 /* If height is non-NULL, then we set it to be the new height.  if it's all
5473  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
5474  */
5475 static gboolean
5476 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
5477                                    GtkTreeIter *iter,
5478                                    gint         depth,
5479                                    gint        *height,
5480                                    GtkRBNode   *node)
5481 {
5482   GtkTreeViewColumn *column;
5483   GList *list;
5484   gboolean retval = FALSE;
5485   gint tmpheight;
5486   gint horizontal_separator;
5487
5488   gtk_widget_style_get (GTK_WIDGET (tree_view),
5489                         "horizontal_separator", &horizontal_separator,
5490                         NULL);
5491
5492   if (height)
5493     *height = -1;
5494
5495   for (list = tree_view->priv->columns; list; list = list->next)
5496     {
5497       gint width;
5498       column = list->data;
5499       if (column->dirty == TRUE)
5500         continue;
5501       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
5502         continue;
5503       if (!column->visible)
5504         continue;
5505
5506       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5507                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5508                                                node->children?TRUE:FALSE);
5509
5510       if (height)
5511         {
5512           gtk_tree_view_column_cell_get_size (column,
5513                                               NULL, NULL, NULL,
5514                                               &width, &tmpheight);
5515           *height = MAX (*height, tmpheight);
5516         }
5517       else
5518         {
5519           gtk_tree_view_column_cell_get_size (column,
5520                                               NULL, NULL, NULL,
5521                                               &width, NULL);
5522         }
5523
5524       if (gtk_tree_view_is_expander_column (tree_view, column) &&
5525           TREE_VIEW_DRAW_EXPANDERS (tree_view))
5526         {
5527           if (depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width)
5528             {
5529               gtk_tree_view_column_cell_set_dirty (column);
5530               retval = TRUE;
5531             }
5532         }
5533       else
5534         {
5535           if (horizontal_separator + width > column->requested_width)
5536             {
5537               gtk_tree_view_column_cell_set_dirty (column);
5538               retval = TRUE;
5539             }
5540         }
5541     }
5542
5543   return retval;
5544 }
5545
5546 static void
5547 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
5548                               GtkRBTree   *tree,
5549                               GtkTreeIter *iter,
5550                               gint         depth)
5551 {
5552   GtkRBNode *temp = tree->root;
5553   GtkTreeViewColumn *column;
5554   GList *list;
5555   GtkTreeIter child;
5556   gboolean is_all_dirty;
5557
5558   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
5559
5560   while (temp->left != tree->nil)
5561     temp = temp->left;
5562
5563   do
5564     {
5565       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
5566       is_all_dirty = TRUE;
5567       for (list = tree_view->priv->columns; list; list = list->next)
5568         {
5569           column = list->data;
5570           if (column->dirty == FALSE)
5571             {
5572               is_all_dirty = FALSE;
5573               break;
5574             }
5575         }
5576
5577       if (is_all_dirty)
5578         return;
5579
5580       gtk_tree_view_discover_dirty_iter (tree_view,
5581                                          iter,
5582                                          depth,
5583                                          NULL,
5584                                          temp);
5585       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
5586           temp->children != NULL)
5587         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
5588       temp = _gtk_rbtree_next (tree, temp);
5589     }
5590   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
5591 }
5592
5593
5594 /* Make sure the node is visible vertically */
5595 static void
5596 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
5597                                   GtkRBTree   *tree,
5598                                   GtkRBNode   *node)
5599 {
5600   gint offset;
5601   gint real_height;
5602
5603   /* We process updates because we want to clear old selected items when we scroll.
5604    * if this is removed, we get a "selection streak" at the bottom. */
5605   if (GTK_WIDGET_REALIZED (tree_view))
5606     gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
5607
5608   real_height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
5609
5610   offset = _gtk_rbtree_node_find_offset (tree, node);
5611
5612   /* we reverse the order, b/c in the unusual case of the
5613    * node's height being taller then the visible area, we'd rather
5614    * have the node flush to the top
5615    */
5616   if (offset + real_height >
5617       tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
5618     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5619                               offset + real_height -
5620                               tree_view->priv->vadjustment->page_size);
5621   if (offset < tree_view->priv->vadjustment->value)
5622     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5623                               offset);
5624
5625 }
5626
5627 static void
5628 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
5629                                     GtkTreeViewColumn *column)
5630 {
5631   if (column == NULL)
5632     return;
5633   if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
5634       (column->button->allocation.x + column->button->allocation.width))
5635     gtk_adjustment_set_value (tree_view->priv->hadjustment,
5636                               column->button->allocation.x + column->button->allocation.width -
5637                               tree_view->priv->hadjustment->page_size);
5638   else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
5639     gtk_adjustment_set_value (tree_view->priv->hadjustment,
5640                               column->button->allocation.x);
5641 }
5642
5643 /* This function could be more efficient.  I'll optimize it if profiling seems
5644  * to imply that it is important */
5645 GtkTreePath *
5646 _gtk_tree_view_find_path (GtkTreeView *tree_view,
5647                           GtkRBTree   *tree,
5648                           GtkRBNode   *node)
5649 {
5650   GtkTreePath *path;
5651   GtkRBTree *tmp_tree;
5652   GtkRBNode *tmp_node, *last;
5653   gint count;
5654
5655   path = gtk_tree_path_new ();
5656
5657   g_return_val_if_fail (node != NULL, path);
5658   g_return_val_if_fail (node != tree->nil, path);
5659
5660   count = 1 + node->left->count;
5661
5662   last = node;
5663   tmp_node = node->parent;
5664   tmp_tree = tree;
5665   while (tmp_tree)
5666     {
5667       while (tmp_node != tmp_tree->nil)
5668         {
5669           if (tmp_node->right == last)
5670             count += 1 + tmp_node->left->count;
5671           last = tmp_node;
5672           tmp_node = tmp_node->parent;
5673         }
5674       gtk_tree_path_prepend_index (path, count - 1);
5675       last = tmp_tree->parent_node;
5676       tmp_tree = tmp_tree->parent_tree;
5677       if (last)
5678         {
5679           count = 1 + last->left->count;
5680           tmp_node = last->parent;
5681         }
5682     }
5683   return path;
5684 }
5685
5686 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
5687  * invalid (ie. points to a node that's not in the tree), *tree and *node are
5688  * both set to NULL.
5689  */
5690 gboolean
5691 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
5692                           GtkTreePath  *path,
5693                           GtkRBTree   **tree,
5694                           GtkRBNode   **node)
5695 {
5696   GtkRBNode *tmpnode = NULL;
5697   GtkRBTree *tmptree = tree_view->priv->tree;
5698   gint *indices = gtk_tree_path_get_indices (path);
5699   gint depth = gtk_tree_path_get_depth (path);
5700   gint i = 0;
5701
5702   *node = NULL;
5703   *tree = NULL;
5704
5705   if (depth == 0 || tmptree == NULL)
5706     return FALSE;
5707   do
5708     {
5709       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5710       ++i;
5711       if (tmpnode == NULL)
5712         {
5713           *tree = NULL;
5714           *node = NULL;
5715           return FALSE;
5716         }
5717       if (i >= depth)
5718         {
5719           *tree = tmptree;
5720           *node = tmpnode;
5721           return FALSE;
5722         }
5723       *tree = tmptree;
5724       *node = tmpnode;
5725       tmptree = tmpnode->children;
5726       if (tmptree == NULL)
5727         return TRUE;
5728     }
5729   while (1);
5730 }
5731
5732 static gboolean
5733 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
5734                                   GtkTreeViewColumn *column)
5735 {
5736   GList *list;
5737
5738   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
5739     return FALSE;
5740
5741   if (tree_view->priv->expander_column != NULL)
5742     {
5743       if (tree_view->priv->expander_column == column)
5744         return TRUE;
5745       return FALSE;
5746     }
5747   else
5748     {
5749       for (list = tree_view->priv->columns; list; list = list->next)
5750         if (((GtkTreeViewColumn *)list->data)->visible)
5751           break;
5752       if (list && list->data == column)
5753         return TRUE;
5754     }
5755   return FALSE;
5756 }
5757
5758 static void
5759 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
5760                                 guint           keyval,
5761                                 guint           modmask,
5762                                 GtkMovementStep step,
5763                                 gint            count)
5764 {
5765
5766   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
5767                                 "move_cursor", 2,
5768                                 GTK_TYPE_ENUM, step,
5769                                 GTK_TYPE_INT, count);
5770
5771   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
5772                                 "move_cursor", 2,
5773                                 GTK_TYPE_ENUM, step,
5774                                 GTK_TYPE_INT, count);
5775
5776   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
5777    return;
5778
5779   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
5780                                 "move_cursor", 2,
5781                                 GTK_TYPE_ENUM, step,
5782                                 GTK_TYPE_INT, count);
5783
5784   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
5785                                 "move_cursor", 2,
5786                                 GTK_TYPE_ENUM, step,
5787                                 GTK_TYPE_INT, count);
5788 }
5789
5790 static gint
5791 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
5792                                  GtkTreeIter  *iter,
5793                                  GtkRBTree    *tree,
5794                                  GtkRBNode    *node)
5795 {
5796   gint retval = FALSE;
5797   do
5798     {
5799       g_return_val_if_fail (node != NULL, FALSE);
5800
5801       if (node->children)
5802         {
5803           GtkTreeIter child;
5804           GtkRBTree *new_tree;
5805           GtkRBNode *new_node;
5806
5807           new_tree = node->children;
5808           new_node = new_tree->root;
5809
5810           while (new_node && new_node->left != new_tree->nil)
5811             new_node = new_node->left;
5812
5813           g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE);
5814           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
5815         }
5816
5817       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
5818         retval = TRUE;
5819       gtk_tree_model_unref_node (model, iter);
5820       node = _gtk_rbtree_next (tree, node);
5821     }
5822   while (gtk_tree_model_iter_next (model, iter));
5823
5824   return retval;
5825 }
5826
5827 static gint
5828 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
5829                                               GtkRBTree   *tree)
5830 {
5831   GtkTreeIter iter;
5832   GtkTreePath *path;
5833   GtkRBNode *node;
5834   gint retval;
5835
5836   if (!tree)
5837     return FALSE;
5838
5839   node = tree->root;
5840   while (node && node->left != tree->nil)
5841     node = node->left;
5842
5843   g_return_val_if_fail (node != NULL, FALSE);
5844   path = _gtk_tree_view_find_path (tree_view, tree, node);
5845   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
5846                            &iter, path);
5847   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
5848   gtk_tree_path_free (path);
5849
5850   return retval;
5851 }
5852
5853 static void
5854 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
5855                                     GtkTreeViewColumn *column)
5856 {
5857   GtkTreeViewColumn *left_column;
5858   GtkTreeViewColumn *cur_column = NULL;
5859   GtkTreeViewColumnReorder *reorder;
5860
5861   GList *tmp_list;
5862   gint left;
5863
5864   /* We want to precalculate the motion list such that we know what column slots
5865    * are available.
5866    */
5867   left_column = NULL;
5868
5869   /* First, identify all possible drop spots */
5870   tmp_list = tree_view->priv->columns;
5871
5872   while (tmp_list)
5873     {
5874       g_assert (tmp_list);
5875
5876       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5877       tmp_list = tmp_list->next;
5878
5879       if (cur_column->visible == FALSE)
5880         continue;
5881
5882       /* If it's not the column moving and func tells us to skip over the column, we continue. */
5883       if (left_column != column && cur_column != column &&
5884           tree_view->priv->column_drop_func &&
5885           ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5886         {
5887           left_column = cur_column;
5888           continue;
5889         }
5890       reorder = g_new (GtkTreeViewColumnReorder, 1);
5891       reorder->left_column = left_column;
5892       left_column = reorder->right_column = cur_column;
5893
5894       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5895     }
5896
5897   /* Add the last one */
5898   if (tree_view->priv->column_drop_func == NULL ||
5899       ((left_column != column) &&
5900        (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
5901     {
5902       reorder = g_new (GtkTreeViewColumnReorder, 1);
5903       reorder->left_column = left_column;
5904       reorder->right_column = NULL;
5905       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5906     }
5907
5908   /* We quickly check to see if it even makes sense to reorder columns. */
5909   /* If there is nothing that can be moved, then we return */
5910
5911   if (tree_view->priv->column_drag_info == NULL)
5912     return;
5913
5914   /* We know there are always 2 slots possbile, as you can always return column. */
5915   /* If that's all there is, return */
5916   if (tree_view->priv->column_drag_info->next->next == NULL &&
5917       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
5918       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
5919     {
5920       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5921         g_free (tmp_list->data);
5922       g_list_free (tree_view->priv->column_drag_info);
5923       tree_view->priv->column_drag_info = NULL;
5924       return;
5925     }
5926   /* We fill in the ranges for the columns, now that we've isolated them */
5927   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5928
5929   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5930     {
5931       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
5932
5933       reorder->left_align = left;
5934       if (tmp_list->next != NULL)
5935         {
5936           g_assert (tmp_list->next->data);
5937           left = reorder->right_align = (reorder->right_column->button->allocation.x +
5938                                          reorder->right_column->button->allocation.width +
5939                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
5940         }
5941       else
5942         {
5943           gint width;
5944
5945           gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
5946           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5947         }
5948     }
5949 }
5950
5951 void
5952 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
5953                                   GtkTreeViewColumn *column)
5954 {
5955   GdkEvent send_event;
5956   GtkAllocation allocation;
5957   gint x, y, width, height;
5958
5959   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
5960
5961   gtk_tree_view_set_column_drag_info (tree_view, column);
5962
5963   if (tree_view->priv->column_drag_info == NULL)
5964     return;
5965
5966   if (tree_view->priv->drag_window == NULL)
5967     {
5968       GdkWindowAttr attributes;
5969       guint attributes_mask;
5970
5971       attributes.window_type = GDK_WINDOW_CHILD;
5972       attributes.wclass = GDK_INPUT_OUTPUT;
5973       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
5974       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
5975       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
5976       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
5977
5978       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
5979                                                      &attributes,
5980                                                      attributes_mask);
5981       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
5982     }
5983
5984   gdk_pointer_ungrab (GDK_CURRENT_TIME);
5985   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5986
5987   gtk_grab_remove (column->button);
5988
5989   send_event.crossing.type = GDK_LEAVE_NOTIFY;
5990   send_event.crossing.send_event = TRUE;
5991   send_event.crossing.window = column->button->window;
5992   send_event.crossing.subwindow = NULL;
5993   send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
5994   send_event.crossing.time = GDK_CURRENT_TIME;
5995
5996   gtk_propagate_event (column->button, &send_event);
5997
5998   send_event.button.type = GDK_BUTTON_RELEASE;
5999   send_event.button.window = GDK_ROOT_PARENT ();
6000   send_event.button.send_event = TRUE;
6001   send_event.button.time = GDK_CURRENT_TIME;
6002   send_event.button.x = -1;
6003   send_event.button.y = -1;
6004   send_event.button.axes = NULL;
6005   send_event.button.state = 0;
6006   send_event.button.button = 1;
6007   send_event.button.device = gdk_device_get_core_pointer ();
6008   send_event.button.x_root = 0;
6009   send_event.button.y_root = 0;
6010
6011   gtk_propagate_event (column->button, &send_event);
6012
6013   gdk_window_move_resize (tree_view->priv->drag_window,
6014                           column->button->allocation.x,
6015                           0,
6016                           column->button->allocation.width,
6017                           column->button->allocation.height);
6018
6019   /* Kids, don't try this at home */
6020   g_object_ref (column->button);
6021   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
6022   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
6023   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
6024   g_object_unref (column->button);
6025
6026   tree_view->priv->drag_column_x = column->button->allocation.x;
6027   allocation = column->button->allocation;
6028   allocation.x = 0;
6029   gtk_widget_size_allocate (column->button, &allocation);
6030   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
6031
6032   tree_view->priv->drag_column = column;
6033   gdk_window_show (tree_view->priv->drag_window);
6034
6035   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
6036   gdk_window_get_size (tree_view->priv->header_window, &width, &height);
6037
6038   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6039   while (gtk_events_pending ())
6040     gtk_main_iteration ();
6041
6042   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
6043   gdk_pointer_grab (tree_view->priv->drag_window,
6044                     FALSE,
6045                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
6046                     NULL, NULL, GDK_CURRENT_TIME);
6047   gdk_keyboard_grab (tree_view->priv->drag_window,
6048                      FALSE,
6049                      GDK_CURRENT_TIME);
6050
6051 }
6052
6053 static void
6054 gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
6055                                 GtkRBTree        *tree,
6056                                 GtkRBNode        *node,
6057                                 GdkRectangle     *clip_rect)
6058 {
6059   GdkRectangle rect;
6060
6061   if (!GTK_WIDGET_REALIZED (tree_view))
6062     return;
6063
6064   rect.x = 0;
6065   rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width);
6066
6067   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
6068   rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
6069
6070   if (clip_rect)
6071     {
6072       GdkRectangle new_rect;
6073
6074       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
6075
6076       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
6077     }
6078   else
6079     {
6080       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
6081     }
6082 }
6083
6084 void
6085 _gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
6086                                 GtkRBTree    *tree,
6087                                 GtkRBNode    *node,
6088                                 GdkRectangle *clip_rect)
6089 {
6090   GdkRectangle rect;
6091
6092   if (!GTK_WIDGET_REALIZED (tree_view))
6093     return;
6094
6095   rect.x = 0;
6096   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
6097
6098   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
6099   rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
6100
6101   if (clip_rect)
6102     {
6103       GdkRectangle new_rect;
6104
6105       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
6106
6107       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
6108     }
6109   else
6110     {
6111       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
6112     }
6113 }
6114
6115 static void
6116 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
6117                                GtkTreePath      *path,
6118                                GdkRectangle     *clip_rect)
6119 {
6120   GtkRBTree *tree = NULL;
6121   GtkRBNode *node = NULL;
6122
6123   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6124
6125   if (tree)
6126     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
6127 }
6128
6129 /* x and y are the mouse position
6130  */
6131 static void
6132 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
6133                           GtkRBTree   *tree,
6134                           GtkRBNode   *node,
6135                           gint         x,
6136                           gint         y)
6137 {
6138   GdkRectangle area;
6139   GtkStateType state;
6140   GtkWidget *widget;
6141   gint x_offset = 0;
6142   gint vertical_separator;
6143   gint expander_size;
6144   GtkExpanderStyle expander_style;
6145
6146   gtk_widget_style_get (GTK_WIDGET (tree_view),
6147                         "vertical_separator", &vertical_separator,
6148                         NULL);
6149   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
6150
6151   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
6152     return;
6153
6154   widget = GTK_WIDGET (tree_view);
6155
6156   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL);
6157
6158   area.x = x_offset;
6159   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
6160   area.width = expander_size + 2;
6161   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
6162
6163   if (node == tree_view->priv->button_pressed_node)
6164     {
6165       if (x >= area.x && x <= (area.x + area.width) &&
6166           y >= area.y && y <= (area.y + area.height))
6167         state = GTK_STATE_ACTIVE;
6168       else
6169         state = GTK_STATE_NORMAL;
6170     }
6171   else
6172     {
6173       if (node == tree_view->priv->prelight_node &&
6174           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
6175         state = GTK_STATE_PRELIGHT;
6176       else
6177         state = GTK_STATE_NORMAL;
6178     }
6179
6180   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
6181     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
6182   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
6183     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
6184   else if (node->children != NULL)
6185     expander_style = GTK_EXPANDER_EXPANDED;
6186   else
6187     expander_style = GTK_EXPANDER_COLLAPSED;
6188
6189   gtk_paint_expander (widget->style,
6190                       tree_view->priv->bin_window,
6191                       state,
6192                       &area,
6193                       widget,
6194                       "treeview",
6195                       area.x + area.width / 2,
6196                       area.y + area.height / 2,
6197                       expander_style);
6198 }
6199
6200 static void
6201 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
6202
6203 {
6204   GtkTreePath *cursor_path;
6205
6206   if ((tree_view->priv->tree == NULL) ||
6207       (! GTK_WIDGET_REALIZED (tree_view)))
6208     return;
6209
6210   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
6211   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6212
6213   cursor_path = NULL;
6214   if (tree_view->priv->cursor)
6215     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6216
6217   if (cursor_path == NULL)
6218     {
6219       cursor_path = gtk_tree_path_new_root ();
6220       gtk_tree_row_reference_free (tree_view->priv->cursor);
6221       tree_view->priv->cursor = NULL;
6222
6223       if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
6224         gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
6225       else
6226         gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
6227     }
6228   gtk_tree_path_free (cursor_path);
6229   if (tree_view->priv->focus_column == NULL)
6230     {
6231       GList *list;
6232       for (list = tree_view->priv->columns; list; list = list->next)
6233         {
6234           if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
6235             {
6236               tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
6237               break;
6238             }
6239         }
6240     }
6241 }
6242
6243 static void
6244 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
6245                                    gint         count)
6246 {
6247   GtkRBTree *cursor_tree = NULL;
6248   GtkRBNode *cursor_node = NULL;
6249   GtkRBTree *new_cursor_tree = NULL;
6250   GtkRBNode *new_cursor_node = NULL;
6251   GtkTreePath *cursor_path = NULL;
6252
6253   cursor_path = NULL;
6254   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
6255     /* FIXME: we lost the cursor; should we get the first? */
6256     return;
6257
6258   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6259   _gtk_tree_view_find_node (tree_view, cursor_path,
6260                             &cursor_tree, &cursor_node);
6261   gtk_tree_path_free (cursor_path);
6262
6263   if (cursor_tree == NULL)
6264     /* FIXME: we lost the cursor; should we get the first? */
6265     return;
6266   if (count == -1)
6267     _gtk_rbtree_prev_full (cursor_tree, cursor_node,
6268                            &new_cursor_tree, &new_cursor_node);
6269   else
6270     _gtk_rbtree_next_full (cursor_tree, cursor_node,
6271                            &new_cursor_tree, &new_cursor_node);
6272
6273   if (new_cursor_node)
6274     {
6275       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
6276       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
6277       gtk_tree_path_free (cursor_path);
6278     }
6279   else
6280     {
6281       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6282     }
6283
6284   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6285 }
6286
6287 static void
6288 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
6289                                         gint         count)
6290 {
6291   GtkRBTree *cursor_tree = NULL;
6292   GtkRBNode *cursor_node = NULL;
6293   GtkTreePath *cursor_path = NULL;
6294   gint y;
6295   gint vertical_separator;
6296
6297   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
6298     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6299   else
6300     /* This is sorta weird.  Focus in should give us a cursor */
6301     return;
6302
6303   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
6304   _gtk_tree_view_find_node (tree_view, cursor_path,
6305                             &cursor_tree, &cursor_node);
6306
6307   gtk_tree_path_free (cursor_path);
6308
6309   if (cursor_tree == NULL)
6310     /* FIXME: we lost the cursor.  Should we try to get one? */
6311     return;
6312   g_return_if_fail (cursor_node != NULL);
6313
6314   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
6315   y += count * tree_view->priv->vadjustment->page_size;
6316   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
6317
6318   _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
6319   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
6320   g_return_if_fail (cursor_path != NULL);
6321   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
6322   gtk_tree_path_free (cursor_path);
6323 }
6324
6325 static void
6326 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
6327                                       gint         count)
6328 {
6329   GtkRBTree *cursor_tree = NULL;
6330   GtkRBNode *cursor_node = NULL;
6331   GtkTreePath *cursor_path = NULL;
6332   GtkTreeViewColumn *column;
6333   GtkTreeIter iter;
6334   GList *list;
6335   gboolean found_column = FALSE;
6336
6337   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
6338     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6339   else
6340     return;
6341
6342   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
6343   if (cursor_tree == NULL)
6344     return;
6345   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
6346     {
6347       gtk_tree_path_free (cursor_path);
6348       return;
6349     }
6350   gtk_tree_path_free (cursor_path);
6351
6352   list = tree_view->priv->columns;
6353   if (tree_view->priv->focus_column)
6354     {
6355       for (list = tree_view->priv->columns; list; list = list->next)
6356         {
6357           if (list->data == tree_view->priv->focus_column)
6358             break;
6359         }
6360     }
6361
6362   while (list)
6363     {
6364       column = list->data;
6365       if (column->visible == FALSE)
6366         goto loop_end;
6367
6368       gtk_tree_view_column_cell_set_cell_data (column,
6369                                                tree_view->priv->model,
6370                                                &iter,
6371                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
6372                                                cursor_node->children?TRUE:FALSE);
6373       if (gtk_tree_view_column_cell_focus (column, count))
6374         {
6375           tree_view->priv->focus_column = column;
6376           found_column = TRUE;
6377           break;
6378         }
6379     loop_end:
6380       if (count == 1)
6381         list = list->next;
6382       else
6383         list = list->prev;
6384     }
6385
6386   if (found_column)
6387     {
6388       _gtk_tree_view_queue_draw_node (tree_view,
6389                                      cursor_tree,
6390                                      cursor_node,
6391                                      NULL);
6392       g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
6393     }
6394   gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
6395 }
6396
6397 static void
6398 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
6399                                      gint         count)
6400 {
6401   GtkRBTree *cursor_tree;
6402   GtkRBNode *cursor_node;
6403   GtkTreePath *path;
6404
6405   g_return_if_fail (tree_view->priv->tree != NULL);
6406
6407   if (count == -1)
6408     {
6409       cursor_tree = tree_view->priv->tree;
6410       cursor_node = cursor_tree->root;
6411       while (cursor_node && cursor_node->left != cursor_tree->nil)
6412         cursor_node = cursor_node->left;
6413     }
6414   else
6415     {
6416       cursor_tree = tree_view->priv->tree;
6417       cursor_node = cursor_tree->root;
6418       do
6419         {
6420           while (cursor_node && cursor_node->right != cursor_tree->nil)
6421             cursor_node = cursor_node->right;
6422           if (cursor_node->children == NULL)
6423             break;
6424
6425           cursor_tree = cursor_node->children;
6426           cursor_node = cursor_tree->root;
6427         }
6428       while (1);
6429     }
6430
6431   path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
6432   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
6433                                             cursor_node,
6434                                             cursor_tree,
6435                                             path,
6436                                             FALSE?GDK_SHIFT_MASK:0);
6437
6438   gtk_tree_row_reference_free (tree_view->priv->cursor);
6439   tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6440   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6441 }
6442
6443 static void
6444 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
6445 {
6446   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
6447     return;
6448   gtk_tree_selection_select_all (tree_view->priv->selection);
6449 }
6450
6451 static void
6452 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
6453                                       gboolean     start_editing)
6454 {
6455   GtkRBTree *cursor_tree = NULL;
6456   GtkRBNode *cursor_node = NULL;
6457   GtkTreePath *cursor_path = NULL;
6458   GdkModifierType state = 0;
6459   cursor_path = NULL;
6460
6461   if (tree_view->priv->cursor)
6462     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6463
6464   if (cursor_path == NULL)
6465     return;
6466
6467   _gtk_tree_view_find_node (tree_view, cursor_path,
6468                             &cursor_tree, &cursor_node);
6469
6470   if (cursor_tree == NULL)
6471     {
6472       gtk_tree_path_free (cursor_path);
6473       return;
6474     }
6475
6476   gtk_get_current_event_state (&state);
6477
6478   if (! (state & GDK_SHIFT_MASK) &&
6479       start_editing &&
6480       tree_view->priv->focus_column)
6481     {
6482       if (gtk_tree_view_start_editing (tree_view, cursor_path))
6483         {
6484           gtk_tree_path_free (cursor_path);
6485           return;
6486         }
6487     }
6488   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
6489                                             cursor_node,
6490                                             cursor_tree,
6491                                             cursor_path,
6492                                             state);
6493
6494   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6495
6496   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6497   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
6498
6499   if (! (state & GDK_SHIFT_MASK))
6500     gtk_tree_view_row_activated (tree_view, cursor_path, tree_view->priv->focus_column);
6501     
6502   gtk_tree_path_free (cursor_path);
6503 }
6504
6505 static void
6506 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
6507 {
6508   GtkRBTree *cursor_tree = NULL;
6509   GtkRBNode *cursor_node = NULL;
6510   GtkTreePath *cursor_path = NULL;
6511
6512   cursor_path = NULL;
6513   if (tree_view->priv->cursor)
6514     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6515
6516   if (cursor_path == NULL)
6517     return;
6518
6519   _gtk_tree_view_find_node (tree_view, cursor_path,
6520                             &cursor_tree, &cursor_node);
6521   if (cursor_tree == NULL)
6522     {
6523       gtk_tree_path_free (cursor_path);
6524       return;
6525     }
6526
6527   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
6528                                             cursor_node,
6529                                             cursor_tree,
6530                                             cursor_path,
6531                                             GDK_CONTROL_MASK);
6532
6533   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6534
6535   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6536   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6537   gtk_tree_path_free (cursor_path);
6538 }
6539
6540
6541
6542 static void
6543 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
6544                                                gboolean     logical,
6545                                                gboolean     expand,
6546                                                gboolean     open_all)
6547 {
6548   GtkTreePath *cursor_path = NULL;
6549   GtkRBTree *tree;
6550   GtkRBNode *node;
6551
6552   cursor_path = NULL;
6553   if (tree_view->priv->cursor)
6554     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6555
6556   if (cursor_path == NULL)
6557     return;
6558
6559   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
6560     return;
6561   
6562   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6563   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6564
6565   if (expand)
6566     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
6567   else
6568     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
6569
6570   gtk_tree_path_free (cursor_path);
6571 }
6572
6573 static void
6574 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
6575 {
6576   GtkRBTree *cursor_tree = NULL;
6577   GtkRBNode *cursor_node = NULL;
6578   GtkTreePath *cursor_path = NULL;
6579
6580   cursor_path = NULL;
6581   if (tree_view->priv->cursor)
6582     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6583
6584   if (cursor_path == NULL)
6585     return;
6586
6587   _gtk_tree_view_find_node (tree_view, cursor_path,
6588                             &cursor_tree, &cursor_node);
6589   if (cursor_tree == NULL)
6590     {
6591       gtk_tree_path_free (cursor_path);
6592       return;
6593     }
6594
6595   if (cursor_tree->parent_node)
6596     {
6597       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6598       cursor_node = cursor_tree->parent_node;
6599       cursor_tree = cursor_tree->parent_tree;
6600
6601       gtk_tree_path_up (cursor_path);
6602       gtk_tree_row_reference_free (tree_view->priv->cursor);
6603       tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
6604       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
6605                                                 cursor_node,
6606                                                 cursor_tree,
6607                                                 cursor_path,
6608                                                 0);
6609     }
6610
6611   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6612
6613   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6614   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6615   gtk_tree_path_free (cursor_path);
6616 }
6617
6618 static void
6619 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
6620 {
6621   GtkWidget *window;
6622   GtkWidget *entry;
6623   GtkWidget *search_dialog;
6624   GdkEventFocus focus_event;
6625
6626   if (tree_view->priv->enable_search == FALSE ||
6627       tree_view->priv->search_column < 0)
6628     return;
6629
6630   search_dialog = g_object_get_data (G_OBJECT (tree_view),
6631                                      GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
6632   if (search_dialog)
6633     return;
6634
6635   /* set up window */
6636   window = gtk_window_new (GTK_WINDOW_POPUP);
6637   gtk_window_set_title (GTK_WINDOW (window), "search dialog");
6638   gtk_container_set_border_width (GTK_CONTAINER (window), 3);
6639   gtk_window_set_modal (GTK_WINDOW (window), TRUE);
6640   g_signal_connect (G_OBJECT (window), "delete_event",
6641                     G_CALLBACK (gtk_tree_view_search_delete_event),
6642                     tree_view);
6643   g_signal_connect (G_OBJECT (window), "key_press_event",
6644                     G_CALLBACK (gtk_tree_view_search_key_press_event),
6645                     tree_view);
6646   g_signal_connect (G_OBJECT (window), "button_press_event",
6647                     G_CALLBACK (gtk_tree_view_search_button_press_event),
6648                     tree_view);
6649
6650   /* add entry */
6651   entry = gtk_entry_new ();
6652   gtk_widget_show (entry);
6653   g_signal_connect (G_OBJECT (entry), "changed",
6654                     G_CALLBACK (gtk_tree_view_search_init), tree_view);
6655   gtk_container_add (GTK_CONTAINER (window), entry);
6656
6657   /* done, show it */
6658   tree_view->priv->search_dialog_position_func (tree_view, window);
6659   gtk_widget_show_all (window);
6660   gtk_widget_grab_focus (entry);
6661
6662   /* send focus-in event */
6663   focus_event.type = GDK_FOCUS_CHANGE;
6664   focus_event.in = TRUE;
6665   gtk_widget_event (entry, (GdkEvent *) &focus_event);
6666
6667   /* position window */
6668
6669   /* yes, we point to the entry's private text thing here, a bit evil */
6670   g_object_set_data (G_OBJECT (window), "gtk-tree-view-text",
6671                      (gchar *) gtk_entry_get_text (GTK_ENTRY (entry)));
6672   g_object_set_data (G_OBJECT (tree_view),
6673                      GTK_TREE_VIEW_SEARCH_DIALOG_KEY, window);
6674
6675   /* search first matching iter */
6676   gtk_tree_view_search_init (entry, tree_view);
6677 }
6678
6679 /* this function returns the new width of the column being resized given
6680  * the column and x position of the cursor; the x cursor position is passed
6681  * in as a pointer and automagicly corrected if it's beyond min/max limits
6682  */
6683 static gint
6684 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
6685                                 gint       i,
6686                                 gint      *x)
6687 {
6688   GtkTreeViewColumn *column;
6689   gint width;
6690
6691   /* first translate the x position from widget->window
6692    * to clist->clist_window
6693    */
6694
6695   column = g_list_nth (tree_view->priv->columns, i)->data;
6696   width = *x - column->button->allocation.x;
6697
6698   /* Clamp down the value */
6699   if (column->min_width == -1)
6700     width = MAX (column->button->requisition.width,
6701                  width);
6702   else
6703     width = MAX (column->min_width,
6704                  width);
6705   if (column->max_width != -1)
6706     width = MIN (width, column->max_width != -1);
6707   *x = column->button->allocation.x + width;
6708
6709   return width;
6710 }
6711
6712
6713 /* Callbacks */
6714 static void
6715 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
6716                                   GtkTreeView   *tree_view)
6717 {
6718   if (GTK_WIDGET_REALIZED (tree_view))
6719     {
6720       gint dy;
6721         
6722       gdk_window_move (tree_view->priv->bin_window,
6723                        - tree_view->priv->hadjustment->value,
6724                        TREE_VIEW_HEADER_HEIGHT (tree_view));
6725       gdk_window_move (tree_view->priv->header_window,
6726                        - tree_view->priv->hadjustment->value,
6727                        0);
6728       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
6729       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
6730
6731       /* update our dy and top_row */
6732       tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
6733       gtk_tree_view_dy_to_top_row (tree_view);
6734       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6735       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
6736     }
6737 }
6738
6739 \f
6740
6741 /* Public methods
6742  */
6743
6744 /**
6745  * gtk_tree_view_new:
6746  *
6747  * Creates a new #GtkTreeView widget.
6748  *
6749  * Return value: A newly created #GtkTreeView widget.
6750  **/
6751 GtkWidget *
6752 gtk_tree_view_new (void)
6753 {
6754   GtkTreeView *tree_view;
6755
6756   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6757
6758   return GTK_WIDGET (tree_view);
6759 }
6760
6761 /**
6762  * gtk_tree_view_new_with_model:
6763  * @model: the model.
6764  *
6765  * Creates a new #GtkTreeView widget with the model initialized to @model.
6766  *
6767  * Return value: A newly created #GtkTreeView widget.
6768  **/
6769 GtkWidget *
6770 gtk_tree_view_new_with_model (GtkTreeModel *model)
6771 {
6772   GtkTreeView *tree_view;
6773
6774   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6775   gtk_tree_view_set_model (tree_view, model);
6776
6777   return GTK_WIDGET (tree_view);
6778 }
6779
6780 /* Public Accessors
6781  */
6782
6783 /**
6784  * gtk_tree_view_get_model:
6785  * @tree_view: a #GtkTreeView
6786  *
6787  * Returns the model the the #GtkTreeView is based on.  Returns %NULL if the
6788  * model is unset.
6789  *
6790  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
6791  **/
6792 GtkTreeModel *
6793 gtk_tree_view_get_model (GtkTreeView *tree_view)
6794 {
6795   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6796
6797   return tree_view->priv->model;
6798 }
6799
6800 /**
6801  * gtk_tree_view_set_model:
6802  * @tree_view: A #GtkTreeNode.
6803  * @model: The model.
6804  *
6805  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
6806  * set, it will remove it before setting the new model.  If @model is %NULL, then
6807  * it will unset the old model.
6808  **/
6809 void
6810 gtk_tree_view_set_model (GtkTreeView  *tree_view,
6811                          GtkTreeModel *model)
6812 {
6813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6814
6815   if (model == tree_view->priv->model)
6816     return;
6817
6818   if (tree_view->priv->model)
6819     {
6820       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
6821
6822       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
6823                                             gtk_tree_view_row_changed, tree_view);
6824       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
6825                                             gtk_tree_view_row_inserted, tree_view);
6826       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
6827                                             gtk_tree_view_row_has_child_toggled, tree_view);
6828       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
6829                                             gtk_tree_view_row_deleted, tree_view);
6830       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
6831                                             gtk_tree_view_rows_reordered, tree_view);
6832       if (tree_view->priv->tree)
6833         {
6834           _gtk_rbtree_free (tree_view->priv->tree);
6835           tree_view->priv->tree = NULL;
6836         }
6837
6838       tree_view->priv->prelight_node = NULL;
6839       tree_view->priv->prelight_tree = NULL;
6840       tree_view->priv->button_pressed_node = NULL;
6841       tree_view->priv->button_pressed_tree = NULL;
6842
6843       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
6844       tree_view->priv->drag_dest_row = NULL;
6845       gtk_tree_row_reference_free (tree_view->priv->cursor);
6846       tree_view->priv->cursor = NULL;
6847       gtk_tree_row_reference_free (tree_view->priv->anchor);
6848       tree_view->priv->anchor = NULL;
6849
6850       g_object_unref (tree_view->priv->model);
6851       tree_view->priv->search_column = -1;
6852       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
6853     }
6854
6855   tree_view->priv->model = model;
6856
6857
6858   if (tree_view->priv->model)
6859     {
6860       gint i;
6861       GtkTreePath *path;
6862       GtkTreeIter iter;
6863
6864
6865       if (tree_view->priv->search_column == -1)
6866         {
6867           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
6868             {
6869               if (gtk_tree_model_get_column_type (model, i) == G_TYPE_STRING)
6870                 {
6871                   tree_view->priv->search_column = i;
6872                   break;
6873                 }
6874             }
6875         }
6876       g_object_ref (tree_view->priv->model);
6877       g_signal_connect (tree_view->priv->model,
6878                         "row_changed",
6879                         G_CALLBACK (gtk_tree_view_row_changed),
6880                         tree_view);
6881       g_signal_connect (tree_view->priv->model,
6882                         "row_inserted",
6883                         G_CALLBACK (gtk_tree_view_row_inserted),
6884                         tree_view);
6885       g_signal_connect (tree_view->priv->model,
6886                         "row_has_child_toggled",
6887                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
6888                         tree_view);
6889       g_signal_connect (tree_view->priv->model,
6890                         "row_deleted",
6891                         G_CALLBACK (gtk_tree_view_row_deleted),
6892                         tree_view);
6893       g_signal_connect (tree_view->priv->model,
6894                         "rows_reordered",
6895                         G_CALLBACK (gtk_tree_view_rows_reordered),
6896                         tree_view);
6897
6898       path = gtk_tree_path_new_root ();
6899       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
6900         {
6901           tree_view->priv->tree = _gtk_rbtree_new ();
6902           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
6903         }
6904       gtk_tree_path_free (path);
6905
6906       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
6907       install_presize_handler (tree_view);
6908     }
6909
6910   g_object_notify (G_OBJECT (tree_view), "model");
6911
6912   if (GTK_WIDGET_REALIZED (tree_view))
6913     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6914 }
6915
6916 /**
6917  * gtk_tree_view_get_selection:
6918  * @tree_view: A #GtkTreeView.
6919  *
6920  * Gets the #GtkTreeSelection associated with @tree_view.
6921  *
6922  * Return value: A #GtkTreeSelection object.
6923  **/
6924 GtkTreeSelection *
6925 gtk_tree_view_get_selection (GtkTreeView *tree_view)
6926 {
6927   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6928
6929   return tree_view->priv->selection;
6930 }
6931
6932 /**
6933  * gtk_tree_view_get_hadjustment:
6934  * @tree_view: A #GtkTreeView
6935  *
6936  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
6937  *
6938  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
6939  * used.
6940  **/
6941 GtkAdjustment *
6942 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
6943 {
6944   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6945
6946   if (tree_view->priv->hadjustment == NULL)
6947     gtk_tree_view_set_hadjustment (tree_view, NULL);
6948
6949   return tree_view->priv->hadjustment;
6950 }
6951
6952 /**
6953  * gtk_tree_view_set_hadjustment:
6954  * @tree_view: A #GtkTreeView
6955  * @adjustment: The #GtkAdjustment to set, or %NULL
6956  *
6957  * Sets the #GtkAdjustment for the current horizontal aspect.
6958  **/
6959 void
6960 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
6961                                GtkAdjustment *adjustment)
6962 {
6963   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6964
6965   gtk_tree_view_set_adjustments (tree_view,
6966                                  adjustment,
6967                                  tree_view->priv->vadjustment);
6968
6969   g_object_notify (G_OBJECT (tree_view), "hadjustment");
6970 }
6971
6972 /**
6973  * gtk_tree_view_get_vadjustment:
6974  * @tree_view: A #GtkTreeView
6975  *
6976  * Gets the #GtkAdjustment currently being used for the vertical aspect.
6977  *
6978  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
6979  * used.
6980  **/
6981 GtkAdjustment *
6982 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
6983 {
6984   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6985
6986   if (tree_view->priv->vadjustment == NULL)
6987     gtk_tree_view_set_vadjustment (tree_view, NULL);
6988
6989   return tree_view->priv->vadjustment;
6990 }
6991
6992 /**
6993  * gtk_tree_view_set_vadjustment:
6994  * @tree_view: A #GtkTreeView
6995  * @adjustment: The #GtkAdjustment to set, or %NULL
6996  *
6997  * Sets the #GtkAdjustment for the current vertical aspect.
6998  **/
6999 void
7000 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
7001                                GtkAdjustment *adjustment)
7002 {
7003   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7004
7005   gtk_tree_view_set_adjustments (tree_view,
7006                                  tree_view->priv->hadjustment,
7007                                  adjustment);
7008
7009   g_object_notify (G_OBJECT (tree_view), "vadjustment");
7010 }
7011
7012 /* Column and header operations */
7013
7014 /**
7015  * gtk_tree_view_get_headers_visible:
7016  * @tree_view: A #GtkTreeView.
7017  *
7018  * Returns %TRUE if the headers on the @tree_view are visible.
7019  *
7020  * Return value: Whether the headers are visible or not.
7021  **/
7022 gboolean
7023 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
7024 {
7025   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7026
7027   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7028 }
7029
7030 /**
7031  * gtk_tree_view_set_headers_visible:
7032  * @tree_view: A #GtkTreeView.
7033  * @headers_visible: %TRUE if the headers are visible
7034  *
7035  * Sets the the visibility state of the headers.
7036  **/
7037 void
7038 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
7039                                    gboolean     headers_visible)
7040 {
7041   gint x, y;
7042   GList *list;
7043   GtkTreeViewColumn *column;
7044
7045   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7046
7047   headers_visible = !! headers_visible;
7048
7049   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
7050     return;
7051
7052   if (headers_visible)
7053     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7054   else
7055     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7056
7057   if (GTK_WIDGET_REALIZED (tree_view))
7058     {
7059       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
7060       if (headers_visible)
7061         {
7062           gdk_window_move_resize (tree_view->priv->bin_window, x + TREE_VIEW_HEADER_HEIGHT (tree_view), y, tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
7063
7064           if (GTK_WIDGET_MAPPED (tree_view))
7065             gtk_tree_view_map_buttons (tree_view);
7066         }
7067       else
7068         {
7069           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
7070
7071           for (list = tree_view->priv->columns; list; list = list->next)
7072             {
7073               column = list->data;
7074               gtk_widget_unmap (column->button);
7075             }
7076           gdk_window_hide (tree_view->priv->header_window);
7077         }
7078     }
7079
7080   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7081   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
7082   tree_view->priv->vadjustment->lower = 0;
7083   tree_view->priv->vadjustment->upper = tree_view->priv->height;
7084   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
7085
7086   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7087
7088   g_object_notify (G_OBJECT (tree_view), "headers_visible");
7089 }
7090
7091
7092 /**
7093  * gtk_tree_view_columns_autosize:
7094  * @tree_view: A #GtkTreeView.
7095  *
7096  * Resizes all columns to their optimal width.
7097  **/
7098 void
7099 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
7100 {
7101   gboolean dirty = FALSE;
7102   GList *list;
7103   GtkTreeViewColumn *column;
7104
7105   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7106
7107   for (list = tree_view->priv->columns; list; list = list->next)
7108     {
7109       column = list->data;
7110       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
7111         continue;
7112       gtk_tree_view_column_cell_set_dirty (column);
7113       dirty = TRUE;
7114     }
7115
7116   if (dirty)
7117     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7118 }
7119
7120 /**
7121  * gtk_tree_view_set_headers_clickable:
7122  * @tree_view: A #GtkTreeView.
7123  * @setting: %TRUE if the columns are clickable.
7124  *
7125  * Allow the column title buttons to be clicked.
7126  **/
7127 void
7128 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
7129                                      gboolean   setting)
7130 {
7131   GList *list;
7132
7133   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7134   g_return_if_fail (tree_view->priv->model != NULL);
7135
7136   for (list = tree_view->priv->columns; list; list = list->next)
7137     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
7138
7139   g_object_notify (G_OBJECT (tree_view), "headers_clickable");
7140 }
7141
7142
7143 /**
7144  * gtk_tree_view_set_rules_hint
7145  * @tree_view: a #GtkTreeView
7146  * @setting: %TRUE if the tree requires reading across rows
7147  *
7148  * This function tells GTK+ that the user interface for your
7149  * application requires users to read across tree rows and associate
7150  * cells with one another. By default, GTK+ will then render the tree
7151  * with alternating row colors. Do <emphasis>not</emphasis> use it
7152  * just because you prefer the appearance of the ruled tree; that's a
7153  * question for the theme. Some themes will draw tree rows in
7154  * alternating colors even when rules are turned off, and users who
7155  * prefer that appearance all the time can choose those themes. You
7156  * should call this function only as a <emphasis>semantic</emphasis>
7157  * hint to the theme engine that your tree makes alternating colors
7158  * useful from a functional standpoint (since it has lots of columns,
7159  * generally).
7160  *
7161  **/
7162 void
7163 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
7164                               gboolean      setting)
7165 {
7166   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7167
7168   setting = setting != FALSE;
7169
7170   if (tree_view->priv->has_rules != setting)
7171     {
7172       tree_view->priv->has_rules = setting;
7173       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7174     }
7175
7176   g_object_notify (G_OBJECT (tree_view), "rules_hint");
7177 }
7178
7179 /**
7180  * gtk_tree_view_get_rules_hint
7181  * @tree_view: a #GtkTreeView
7182  *
7183  * Gets the setting set by gtk_tree_view_set_rules_hint().
7184  *
7185  * Return value: %TRUE if rules are useful for the user of this tree
7186  **/
7187 gboolean
7188 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
7189 {
7190   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7191
7192   return tree_view->priv->has_rules;
7193 }
7194
7195 /* Public Column functions
7196  */
7197
7198 /**
7199  * gtk_tree_view_append_column:
7200  * @tree_view: A #GtkTreeView.
7201  * @column: The #GtkTreeViewColumn to add.
7202  *
7203  * Appends @column to the list of columns.
7204  *
7205  * Return value: The number of columns in @tree_view after appending.
7206  **/
7207 gint
7208 gtk_tree_view_append_column (GtkTreeView       *tree_view,
7209                              GtkTreeViewColumn *column)
7210 {
7211   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7212   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7213   g_return_val_if_fail (column->tree_view == NULL, -1);
7214
7215   return gtk_tree_view_insert_column (tree_view, column, -1);
7216 }
7217
7218
7219 /**
7220  * gtk_tree_view_remove_column:
7221  * @tree_view: A #GtkTreeView.
7222  * @column: The #GtkTreeViewColumn to remove.
7223  *
7224  * Removes @column from @tree_view.
7225  *
7226  * Return value: The number of columns in @tree_view after removing.
7227  **/
7228 gint
7229 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
7230                              GtkTreeViewColumn *column)
7231 {
7232   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7233   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7234   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
7235
7236   _gtk_tree_view_column_unset_tree_view (column);
7237
7238   if (tree_view->priv->focus_column == column)
7239     tree_view->priv->focus_column = NULL;
7240
7241   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
7242   tree_view->priv->n_columns--;
7243
7244   if (GTK_WIDGET_REALIZED (tree_view))
7245     {
7246       GList *list;
7247
7248       _gtk_tree_view_column_unrealize_button (column);
7249       for (list = tree_view->priv->columns; list; list = list->next)
7250         {
7251           GtkTreeViewColumn *tmp_column;
7252
7253           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
7254           if (tmp_column->visible)
7255             gtk_tree_view_column_cell_set_dirty (tmp_column);
7256         }
7257
7258       if (tree_view->priv->n_columns == 0 &&
7259           gtk_tree_view_get_headers_visible (tree_view))
7260         gdk_window_hide (tree_view->priv->header_window);
7261
7262       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7263     }
7264
7265   g_object_unref (G_OBJECT (column));
7266   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
7267
7268   return tree_view->priv->n_columns;
7269 }
7270
7271 /**
7272  * gtk_tree_view_insert_column:
7273  * @tree_view: A #GtkTreeView.
7274  * @column: The #GtkTreeViewColumn to be inserted.
7275  * @position: The position to insert @column in.
7276  *
7277  * This inserts the @column into the @tree_view at @position.  If @position is
7278  * -1, then the column is inserted at the end.
7279  *
7280  * Return value: The number of columns in @tree_view after insertion.
7281  **/
7282 gint
7283 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
7284                              GtkTreeViewColumn *column,
7285                              gint               position)
7286 {
7287   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7288   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7289   g_return_val_if_fail (column->tree_view == NULL, -1);
7290
7291   g_object_ref (G_OBJECT (column));
7292   gtk_object_sink (GTK_OBJECT (column));
7293
7294   if (tree_view->priv->n_columns == 0 &&
7295       GTK_WIDGET_REALIZED (tree_view) &&
7296       gtk_tree_view_get_headers_visible (tree_view))
7297     {
7298       gdk_window_show (tree_view->priv->header_window);
7299     }
7300
7301   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
7302                                             column, position);
7303   tree_view->priv->n_columns++;
7304
7305   _gtk_tree_view_column_set_tree_view (column, tree_view);
7306
7307   if (GTK_WIDGET_REALIZED (tree_view))
7308     {
7309       GList *list;
7310
7311       _gtk_tree_view_column_realize_button (column);
7312
7313       for (list = tree_view->priv->columns; list; list = list->next)
7314         {
7315           column = GTK_TREE_VIEW_COLUMN (list->data);
7316           if (column->visible)
7317             gtk_tree_view_column_cell_set_dirty (column);
7318         }
7319       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7320     }
7321
7322   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
7323
7324   return tree_view->priv->n_columns;
7325 }
7326
7327 /**
7328  * gtk_tree_view_insert_column_with_attributes:
7329  * @tree_view: A #GtkTreeView
7330  * @position: The position to insert the new column in.
7331  * @title: The title to set the header to.
7332  * @cell: The #GtkCellRenderer.
7333  * @Varargs: A %NULL-terminated list of attributes.
7334  *
7335  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
7336  * @position.  If @position is -1, then the newly created column is inserted at
7337  * the end.  The column is initialized with the attributes given.
7338  *
7339  * Return value: The number of columns in @tree_view after insertion.
7340  **/
7341 gint
7342 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
7343                                              gint             position,
7344                                              gchar           *title,
7345                                              GtkCellRenderer *cell,
7346                                              ...)
7347 {
7348   GtkTreeViewColumn *column;
7349   gchar *attribute;
7350   va_list args;
7351   gint column_id;
7352
7353   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7354
7355   column = gtk_tree_view_column_new ();
7356
7357   gtk_tree_view_column_set_title (column, title);
7358   gtk_tree_view_column_pack_start (column, cell, TRUE);
7359
7360   va_start (args, cell);
7361
7362   attribute = va_arg (args, gchar *);
7363
7364   while (attribute != NULL)
7365     {
7366       column_id = va_arg (args, gint);
7367       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
7368       attribute = va_arg (args, gchar *);
7369     }
7370
7371   va_end (args);
7372
7373   gtk_tree_view_insert_column (tree_view, column, position);
7374
7375   return tree_view->priv->n_columns;
7376 }
7377
7378 /**
7379  * gtk_tree_view_insert_column_with_data_func:
7380  * @tree_view: a #GtkTreeView
7381  * @position: Position to insert, -1 for append
7382  * @title: column title
7383  * @cell: cell renderer for column
7384  * @func: function to set attributes of cell renderer
7385  * @data: data for @func
7386  * @dnotify: destroy notifier for @data
7387  *
7388  * Convenience function that inserts a new column into the #GtkTreeView
7389  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
7390  * attributes (normally using data from the model). See also
7391  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
7392  *
7393  * Return value: number of columns in the tree view post-insert
7394  **/
7395 gint
7396 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
7397                                              gint                       position,
7398                                              gchar                     *title,
7399                                              GtkCellRenderer           *cell,
7400                                              GtkTreeCellDataFunc        func,
7401                                              gpointer                   data,
7402                                              GDestroyNotify             dnotify)
7403 {
7404   GtkTreeViewColumn *column;
7405
7406   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7407
7408   column = gtk_tree_view_column_new ();
7409
7410   gtk_tree_view_column_set_title (column, title);
7411   gtk_tree_view_column_pack_start (column, cell, TRUE);
7412   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
7413
7414   gtk_tree_view_insert_column (tree_view, column, position);
7415
7416   return tree_view->priv->n_columns;
7417 }
7418
7419 /**
7420  * gtk_tree_view_get_column:
7421  * @tree_view: A #GtkTreeView.
7422  * @n: The position of the column, counting from 0.
7423  *
7424  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
7425  *
7426  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
7427  * range of columns.
7428  **/
7429 GtkTreeViewColumn *
7430 gtk_tree_view_get_column (GtkTreeView *tree_view,
7431                           gint         n)
7432 {
7433   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7434
7435   if (n < 0 || n >= tree_view->priv->n_columns)
7436     return NULL;
7437
7438   if (tree_view->priv->columns == NULL)
7439     return NULL;
7440
7441   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
7442 }
7443
7444 /**
7445  * gtk_tree_view_get_columns:
7446  * @tree_view: A #GtkTreeView
7447  *
7448  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
7449  * The returned list must be freed with g_list_free ().
7450  *
7451  * Return value: A list of #GtkTreeViewColumn s
7452  **/
7453 GList *
7454 gtk_tree_view_get_columns (GtkTreeView *tree_view)
7455 {
7456   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7457
7458   return g_list_copy (tree_view->priv->columns);
7459 }
7460
7461 /**
7462  * gtk_tree_view_move_column_after:
7463  * @tree_view: A #GtkTreeView
7464  * @column: The #GtkTreeViewColumn to be moved.
7465  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
7466  *
7467  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
7468  * @column is placed in the first position.
7469  **/
7470 void
7471 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
7472                                  GtkTreeViewColumn *column,
7473                                  GtkTreeViewColumn *base_column)
7474 {
7475   GList *column_list_el, *base_el = NULL;
7476
7477   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7478
7479   column_list_el = g_list_find (tree_view->priv->columns, column);
7480   g_return_if_fail (column_list_el != NULL);
7481
7482   if (base_column)
7483     {
7484       base_el = g_list_find (tree_view->priv->columns, base_column);
7485       g_return_if_fail (base_el != NULL);
7486     }
7487
7488   if (column_list_el->prev == base_el)
7489     return;
7490
7491   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
7492   if (base_el == NULL)
7493     {
7494       column_list_el->prev = NULL;
7495       column_list_el->next = tree_view->priv->columns;
7496       if (column_list_el->next)
7497         column_list_el->next->prev = column_list_el;
7498       tree_view->priv->columns = column_list_el;
7499     }
7500   else
7501     {
7502       column_list_el->prev = base_el;
7503       column_list_el->next = base_el->next;
7504       if (column_list_el->next)
7505         column_list_el->next->prev = column_list_el;
7506       base_el->next = column_list_el;
7507     }
7508
7509   if (GTK_WIDGET_REALIZED (tree_view))
7510     {
7511       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7512       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
7513     }
7514
7515   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
7516 }
7517
7518 /**
7519  * gtk_tree_view_set_expander_column:
7520  * @tree_view: A #GtkTreeView
7521  * @column: %NULL, or the column to draw the expander arrow at.
7522  *
7523  * Sets the column to draw the expander arrow at. It must be in @tree_view.  If
7524  * @column is %NULL, then the expander arrow is always at the first visible
7525  * column.
7526  **/
7527 void
7528 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
7529                                    GtkTreeViewColumn *column)
7530 {
7531   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7532   if (column != NULL)
7533     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7534
7535   if (tree_view->priv->expander_column != column)
7536     {
7537       GList *list;
7538
7539       if (column)
7540         {
7541           /* Confirm that column is in tree_view */
7542           for (list = tree_view->priv->columns; list; list = list->next)
7543             if (list->data == column)
7544               break;
7545           g_return_if_fail (list != NULL);
7546         }
7547
7548       tree_view->priv->expander_column = column;
7549       g_object_notify (G_OBJECT (tree_view), "expander_column");
7550     }
7551 }
7552
7553 /**
7554  * gtk_tree_view_get_expander_column:
7555  * @tree_view: A #GtkTreeView
7556  *
7557  * Returns the column that is the current expander column.  This
7558  * column has the expander arrow drawn next to it.
7559  *
7560  * Return value: The expander column.
7561  **/
7562 GtkTreeViewColumn *
7563 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
7564 {
7565   GList *list;
7566
7567   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7568
7569   for (list = tree_view->priv->columns; list; list = list->next)
7570     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
7571       return (GtkTreeViewColumn *) list->data;
7572   return NULL;
7573 }
7574
7575
7576 /**
7577  * gtk_tree_view_set_column_drag_function:
7578  * @tree_view: A #GtkTreeView.
7579  * @func: A function to determine which columns are reorderable, or %NULL.
7580  * @user_data: User data to be passed to @func, or %NULL
7581  * @destroy: Destroy notifier for @user_data, or %NULL
7582  *
7583  * Sets a user function for determining where a column may be dropped when
7584  * dragged.  This function is called on every column pair in turn at the
7585  * beginning of a column drag to determine where a drop can take place.  The
7586  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
7587  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
7588  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
7589  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
7590  * @tree_view reverts to the default behavior of allowing all columns to be
7591  * dropped everywhere.
7592  **/
7593 void
7594 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
7595                                         GtkTreeViewColumnDropFunc  func,
7596                                         gpointer                   user_data,
7597                                         GtkDestroyNotify           destroy)
7598 {
7599   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7600
7601   if (tree_view->priv->column_drop_func_data_destroy)
7602     (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
7603
7604   tree_view->priv->column_drop_func = func;
7605   tree_view->priv->column_drop_func_data = user_data;
7606   tree_view->priv->column_drop_func_data_destroy = destroy;
7607 }
7608
7609 /**
7610  * gtk_tree_view_scroll_to_point:
7611  * @tree_view: a #GtkTreeView
7612  * @tree_x: X coordinate of new top-left pixel of visible area
7613  * @tree_y: Y coordinate of new top-left pixel of visible area
7614  *
7615  * Scrolls the tree view such that the top-left corner of the visible
7616  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
7617  * in tree window coordinates.  The @tree_view must be realized before
7618  * this function is called.  If it isn't, you probably want to be
7619  * using gtk_tree_view_scroll_to_cell().
7620  **/
7621 void
7622 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
7623                                gint         tree_x,
7624                                gint         tree_y)
7625 {
7626   GtkAdjustment *hadj;
7627   GtkAdjustment *vadj;
7628
7629   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7630   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
7631
7632   hadj = tree_view->priv->hadjustment;
7633   vadj = tree_view->priv->vadjustment;
7634
7635   gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
7636   gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
7637 }
7638
7639 /**
7640  * gtk_tree_view_scroll_to_cell
7641  * @tree_view: A #GtkTreeView.
7642  * @path: The path of the row to move to, or %NULL.
7643  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
7644  * @use_align: whether to use alignment arguments, or %FALSE.
7645  * @row_align: The vertical alignment of the row specified by @path.
7646  * @col_align: The horizontal alignment of the column specified by @column.
7647  *
7648  * Moves the alignments of @tree_view to the position specified by @column and
7649  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
7650  * if @path is %NULL no vertical scrolling occurs.  @row_align determines where
7651  * the row is placed, and @col_align determines where @column is placed.  Both
7652  * are expected to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0
7653  * means right/bottom alignment, 0.5 means center.  If @use_align is %FALSE,
7654  * then the alignment arguments are ignored, and the tree does the minimum
7655  * amount of work to scroll the cell onto the screen.
7656  **/
7657 void
7658 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
7659                               GtkTreePath       *path,
7660                               GtkTreeViewColumn *column,
7661                               gboolean           use_align,
7662                               gfloat             row_align,
7663                               gfloat             col_align)
7664 {
7665   GdkRectangle cell_rect;
7666   GdkRectangle vis_rect;
7667   gint dest_x, dest_y;
7668   gfloat within_margin = 0;
7669
7670   /* FIXME work on unmapped/unrealized trees? maybe implement when
7671    * we do incremental reflow for trees
7672    */
7673
7674   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7675   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
7676   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
7677   g_return_if_fail (path != NULL || column != NULL);
7678
7679   row_align = CLAMP (row_align, 0.0, 1.0);
7680   col_align = CLAMP (col_align, 0.0, 1.0);
7681
7682   if (! GTK_WIDGET_REALIZED (tree_view))
7683     {
7684       if (path)
7685         tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
7686       if (column)
7687         tree_view->priv->scroll_to_column = column;
7688       tree_view->priv->scroll_to_use_align = use_align;
7689       tree_view->priv->scroll_to_row_align = row_align;
7690       tree_view->priv->scroll_to_col_align = col_align;
7691
7692       return;
7693     }
7694
7695   gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
7696   gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
7697
7698   dest_x = vis_rect.x;
7699   dest_y = vis_rect.y;
7700
7701   if (column)
7702     {
7703       if (use_align)
7704         {
7705           dest_x = cell_rect.x + cell_rect.width * row_align - vis_rect.width * row_align;
7706         }
7707       else
7708         {
7709           if (cell_rect.x < vis_rect.x)
7710             dest_x = cell_rect.x - vis_rect.width * within_margin;
7711           else if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
7712             dest_x = cell_rect.x + cell_rect.width - vis_rect.width * (1 - within_margin);
7713         }
7714     }
7715
7716   if (path)
7717     {
7718       if (use_align)
7719         {
7720           dest_y = cell_rect.y + cell_rect.height * col_align - vis_rect.height * col_align;
7721         }
7722       else
7723         {
7724           if (cell_rect.y < vis_rect.y)
7725             dest_y = cell_rect.y - vis_rect.height * within_margin;
7726           else if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
7727             dest_y = cell_rect.y + cell_rect.height - vis_rect.height * (1 - within_margin);
7728         }
7729     }
7730
7731   gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
7732 }
7733
7734
7735 /**
7736  * gtk_tree_view_row_activated:
7737  * @tree_view: A #GtkTreeView
7738  * @path: The #GtkTreePath to be activated.
7739  * @column: The #GtkTreeViewColumn to be activated.
7740  *
7741  * Activates the cell determined by @path and @column.
7742  **/
7743 void
7744 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
7745                              GtkTreePath       *path,
7746                              GtkTreeViewColumn *column)
7747 {
7748   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7749
7750   g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
7751 }
7752
7753
7754 static void
7755 gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
7756                                  GtkRBNode  *node,
7757                                  gpointer  data)
7758 {
7759   GtkTreeView *tree_view = data;
7760
7761   if (node->children)
7762     _gtk_rbtree_traverse (node->children,
7763                           node->children->root,
7764                           G_PRE_ORDER,
7765                           gtk_tree_view_expand_all_helper,
7766                           data);
7767   else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
7768     {
7769       GtkTreePath *path;
7770       GtkTreeIter iter;
7771       GtkTreeIter child;
7772
7773       node->children = _gtk_rbtree_new ();
7774       node->children->parent_tree = tree;
7775       node->children->parent_node = node;
7776       path = _gtk_tree_view_find_path (tree_view, tree, node);
7777       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7778       gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
7779       gtk_tree_view_build_tree (tree_view,
7780                                 node->children,
7781                                 &child,
7782                                 gtk_tree_path_get_depth (path) + 1,
7783                                 TRUE);
7784       gtk_tree_path_free (path);
7785     }
7786 }
7787
7788 /**
7789  * gtk_tree_view_expand_all:
7790  * @tree_view: A #GtkTreeView.
7791  *
7792  * Recursively expands all nodes in the @tree_view.
7793  **/
7794 void
7795 gtk_tree_view_expand_all (GtkTreeView *tree_view)
7796 {
7797   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7798   g_return_if_fail (tree_view->priv->tree != NULL);
7799
7800   _gtk_rbtree_traverse (tree_view->priv->tree,
7801                         tree_view->priv->tree->root,
7802                         G_PRE_ORDER,
7803                         gtk_tree_view_expand_all_helper,
7804                         tree_view);
7805 }
7806
7807 /* Timeout to animate the expander during expands and collapses */
7808 static gboolean
7809 expand_collapse_timeout (gpointer data)
7810 {
7811   GtkTreeView *tree_view = data;
7812   GtkRBNode *node;
7813   GtkRBTree *tree;
7814   gboolean expanding;
7815   gboolean redraw;
7816
7817   GDK_THREADS_ENTER ();
7818
7819   redraw = FALSE;
7820   expanding = TRUE;
7821
7822   node = tree_view->priv->expanded_collapsed_node;
7823   tree = tree_view->priv->expanded_collapsed_tree;
7824
7825   if (node->children == NULL)
7826     expanding = FALSE;
7827
7828   if (expanding)
7829     {
7830       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
7831         {
7832           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
7833           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
7834
7835           redraw = TRUE;
7836
7837         }
7838       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
7839         {
7840           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
7841
7842           redraw = TRUE;
7843         }
7844     }
7845   else
7846     {
7847       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
7848         {
7849           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
7850           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
7851
7852           redraw = TRUE;
7853         }
7854       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
7855         {
7856           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
7857
7858           redraw = TRUE;
7859
7860         }
7861     }
7862
7863   if (redraw)
7864     {
7865       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
7866
7867       GDK_THREADS_LEAVE ();
7868
7869       return TRUE;
7870     }
7871
7872   GDK_THREADS_LEAVE ();
7873
7874   return FALSE;
7875 }
7876
7877 /**
7878  * gtk_tree_view_collapse_all:
7879  * @tree_view: A #GtkTreeView.
7880  *
7881  * Recursively collapses all visible, expanded nodes in @tree_view.
7882  **/
7883 void
7884 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
7885 {
7886   GtkRBTree *tree;
7887   GtkRBNode *node;
7888   GtkTreePath *path;
7889   guint *indices;
7890
7891   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7892   g_return_if_fail (tree_view->priv->tree != NULL);
7893
7894   path = gtk_tree_path_new ();
7895   gtk_tree_path_down (path);
7896   indices = gtk_tree_path_get_indices (path);
7897
7898   tree = tree_view->priv->tree;
7899   node = tree->root;
7900   while (node && node->left != tree->nil)
7901     node = node->left;
7902
7903   while (node)
7904     {
7905       if (node->children)
7906         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
7907       indices[0]++;
7908       node = _gtk_rbtree_next (tree, node);
7909     }
7910
7911   gtk_tree_path_free (path);
7912 }
7913
7914 /* FIXME the bool return values for expand_row and collapse_row are
7915  * not analagous; they should be TRUE if the row had children and
7916  * was not already in the requested state.
7917  */
7918
7919
7920 static gboolean
7921 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
7922                                GtkTreePath *path,
7923                                GtkRBTree   *tree,
7924                                GtkRBNode   *node,
7925                                gboolean     open_all,
7926                                gboolean     animate)
7927 {
7928   GtkTreeIter iter;
7929   GtkTreeIter temp;
7930   gboolean expand;
7931
7932
7933   if (node->children)
7934     return TRUE;
7935   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
7936     return FALSE;
7937
7938   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7939   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
7940     return FALSE;
7941
7942   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
7943
7944   if (expand)
7945     return FALSE;
7946
7947   node->children = _gtk_rbtree_new ();
7948   node->children->parent_tree = tree;
7949   node->children->parent_node = node;
7950
7951   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
7952
7953   gtk_tree_view_build_tree (tree_view,
7954                             node->children,
7955                             &temp,
7956                             gtk_tree_path_get_depth (path) + 1,
7957                             open_all);
7958
7959   if (tree_view->priv->expand_collapse_timeout)
7960     {
7961       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
7962       tree_view->priv->expand_collapse_timeout = 0;
7963     }
7964
7965   if (tree_view->priv->expanded_collapsed_node != NULL)
7966     {
7967       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
7968       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
7969
7970       tree_view->priv->expanded_collapsed_node = NULL;
7971     }
7972
7973   if (animate)
7974     {
7975       tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
7976       tree_view->priv->expanded_collapsed_node = node;
7977       tree_view->priv->expanded_collapsed_tree = tree;
7978
7979       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
7980     }
7981
7982   if (GTK_WIDGET_MAPPED (tree_view))
7983     install_presize_handler (tree_view);
7984
7985   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
7986   return TRUE;
7987 }
7988
7989
7990 /**
7991  * gtk_tree_view_expand_row:
7992  * @tree_view: a #GtkTreeView
7993  * @path: path to a row
7994  * @open_all: whether to recursively expand, or just expand immediate children
7995  *
7996  * Opens the row so its children are visible.
7997  *
7998  * Return value: %TRUE if the row existed and had children
7999  **/
8000 gboolean
8001 gtk_tree_view_expand_row (GtkTreeView *tree_view,
8002                           GtkTreePath *path,
8003                           gboolean     open_all)
8004 {
8005   GtkRBTree *tree;
8006   GtkRBNode *node;
8007
8008   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8009   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
8010   g_return_val_if_fail (path != NULL, FALSE);
8011
8012   if (_gtk_tree_view_find_node (tree_view,
8013                                 path,
8014                                 &tree,
8015                                 &node))
8016     return FALSE;
8017
8018   if (tree != NULL)
8019     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
8020   else
8021     return FALSE;
8022 }
8023
8024 static gboolean
8025 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
8026                                  GtkTreePath *path,
8027                                  GtkRBTree   *tree,
8028                                  GtkRBNode   *node,
8029                                  gboolean     animate)
8030 {
8031   GtkTreeIter iter;
8032   GtkTreeIter children;
8033   gboolean collapse;
8034   gint x, y;
8035   GList *list;
8036
8037   if (node->children == NULL)
8038     return FALSE;
8039
8040   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8041
8042   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
8043
8044   if (collapse)
8045     return FALSE;
8046
8047   /* if the prelighted node is a child of us, we want to unprelight it.  We have
8048    * a chance to prelight the correct node below */
8049
8050   if (tree_view->priv->prelight_tree)
8051     {
8052       GtkRBTree *parent_tree;
8053       GtkRBNode *parent_node;
8054
8055       parent_tree = tree_view->priv->prelight_tree->parent_tree;
8056       parent_node = tree_view->priv->prelight_tree->parent_node;
8057       while (parent_tree)
8058         {
8059           if (parent_tree == tree && parent_node == node)
8060             {
8061               ensure_unprelighted (tree_view);
8062               break;
8063             }
8064           parent_node = parent_tree->parent_node;
8065           parent_tree = parent_tree->parent_tree;
8066         }
8067     }
8068
8069   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
8070
8071   for (list = tree_view->priv->columns; list; list = list->next)
8072     {
8073       GtkTreeViewColumn *column = list->data;
8074
8075       if (column->visible == FALSE)
8076         continue;
8077       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8078         gtk_tree_view_column_cell_set_dirty (column);
8079     }
8080
8081   if (tree_view->priv->destroy_count_func)
8082     {
8083       GtkTreePath *child_path;
8084       gint child_count = 0;
8085       child_path = gtk_tree_path_copy (path);
8086       gtk_tree_path_down (child_path);
8087       if (node->children)
8088         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8089       (* tree_view->priv->destroy_count_func) (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
8090       gtk_tree_path_free (child_path);
8091     }
8092
8093   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
8094     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0);
8095   _gtk_rbtree_remove (node->children);
8096
8097   if (tree_view->priv->expand_collapse_timeout)
8098     {
8099       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
8100       tree_view->priv->expand_collapse_timeout = 0;
8101     }
8102   
8103   if (tree_view->priv->expanded_collapsed_node != NULL)
8104     {
8105       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8106       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8107       
8108       tree_view->priv->expanded_collapsed_node = NULL;
8109     }
8110
8111   if (animate)
8112     {
8113       tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
8114       tree_view->priv->expanded_collapsed_node = node;
8115       tree_view->priv->expanded_collapsed_tree = tree;
8116
8117       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8118     }
8119   
8120   if (GTK_WIDGET_MAPPED (tree_view))
8121     {
8122       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8123     }
8124
8125   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8126     {
8127       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8128
8129       if (gtk_tree_path_is_ancestor (path, cursor_path))
8130         {
8131           gtk_tree_row_reference_free (tree_view->priv->cursor);
8132           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
8133                                                                       tree_view->priv->model,
8134                                                                       path);
8135         }
8136       gtk_tree_path_free (cursor_path);
8137     }
8138
8139   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
8140       {
8141       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
8142       if (gtk_tree_path_is_ancestor (path, anchor_path))
8143         {
8144           gtk_tree_row_reference_free (tree_view->priv->anchor);
8145           tree_view->priv->anchor = NULL;
8146         }
8147       gtk_tree_path_free (anchor_path);
8148
8149     }
8150
8151   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
8152
8153   /* now that we've collapsed all rows, we want to try to set the prelight
8154    * again. To do this, we fake a motion event and send it to ourselves. */
8155
8156   if (gdk_window_at_pointer (&x, &y) == tree_view->priv->bin_window)
8157     {
8158       GdkEventMotion event;
8159       event.window = tree_view->priv->bin_window;
8160       event.x = x;
8161       event.y = y;
8162
8163       /* despite the fact this isn't a real event, I'm almost positive it will
8164        * never trigger a drag event.  maybe_drag is the only function that uses
8165        * more than just event.x and event.y. */
8166       gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
8167     }
8168   return TRUE;
8169 }
8170
8171 /**
8172  * gtk_tree_view_collapse_row:
8173  * @tree_view: a #GtkTreeView
8174  * @path: path to a row in the @tree_view
8175  *
8176  * Collapses a row (hides its child rows, if they exist).
8177  *
8178  * Return value: %TRUE if the row was collapsed.
8179  **/
8180 gboolean
8181 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
8182                             GtkTreePath *path)
8183 {
8184   GtkRBTree *tree;
8185   GtkRBNode *node;
8186
8187   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8188   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
8189   g_return_val_if_fail (path != NULL, FALSE);
8190
8191   if (_gtk_tree_view_find_node (tree_view,
8192                                 path,
8193                                 &tree,
8194                                 &node))
8195     return FALSE;
8196
8197   if (tree == NULL || node->children == NULL)
8198     return FALSE;
8199
8200   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
8201 }
8202
8203 static void
8204 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
8205                                         GtkRBTree              *tree,
8206                                         GtkTreePath            *path,
8207                                         GtkTreeViewMappingFunc  func,
8208                                         gpointer                user_data)
8209 {
8210   GtkRBNode *node;
8211
8212   if (tree == NULL || tree->root == NULL)
8213     return;
8214
8215   node = tree->root;
8216
8217   while (node && node->left != tree->nil)
8218     node = node->left;
8219
8220   while (node)
8221     {
8222       if (node->children)
8223         {
8224           gtk_tree_path_down (path);
8225           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
8226           gtk_tree_path_up (path);
8227           (* func) (tree_view, path, user_data);
8228         }
8229       gtk_tree_path_next (path);
8230       node = _gtk_rbtree_next (tree, node);
8231     }
8232 }
8233
8234 /**
8235  * gtk_tree_view_map_expanded_rows:
8236  * @tree_view: A #GtkTreeView
8237  * @func: A function to be called
8238  * @data: User data to be passed to the function.
8239  *
8240  * Calls @func on all expanded rows.
8241  **/
8242 void
8243 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
8244                                  GtkTreeViewMappingFunc  func,
8245                                  gpointer                user_data)
8246 {
8247   GtkTreePath *path;
8248
8249   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8250   g_return_if_fail (func != NULL);
8251
8252   path = gtk_tree_path_new_root ();
8253
8254   gtk_tree_view_map_expanded_rows_helper (tree_view,
8255                                           tree_view->priv->tree,
8256                                           path, func, user_data);
8257
8258   gtk_tree_path_free (path);
8259 }
8260
8261 /**
8262  * gtk_tree_view_row_expanded:
8263  * @tree_view: A #GtkTreeView.
8264  * @path: A #GtkTreePath to test expansion state.
8265  *
8266  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
8267  *
8268  * Return value: %TRUE if #path is expanded.
8269  **/
8270 gboolean
8271 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
8272                             GtkTreePath *path)
8273 {
8274   GtkRBTree *tree;
8275   GtkRBNode *node;
8276
8277   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8278   g_return_val_if_fail (path != NULL, FALSE);
8279
8280   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
8281
8282   if (node == NULL)
8283     return FALSE;
8284
8285   return (node->children != NULL);
8286 }
8287
8288 static GtkTargetEntry row_targets[] = {
8289   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
8290 };
8291
8292
8293 /**
8294  * gtk_tree_view_get_reorderable:
8295  * @tree_view: a #GtkTreeView
8296  *
8297  * Retrieves whether the user can reorder the tree via drag-and-drop. See
8298  * gtk_tree_view_set_reorderable().
8299  *
8300  * Return value: %TRUE if the tree can be reordered.
8301  **/
8302 gboolean
8303 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
8304 {
8305   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8306
8307   return tree_view->priv->reorderable;
8308 }
8309
8310 /**
8311  * gtk_tree_view_set_reorderable:
8312  * @tree_view: A #GtkTreeView.
8313  * @reorderable: %TRUE, if the tree can be reordered.
8314  *
8315  * This function is a convenience function to allow you to reorder models that
8316  * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
8317  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
8318  * the user can reorder the model by dragging and dropping columns.  The
8319  * developer can listen to these changes by connecting to the model's
8320  * signals.
8321  *
8322  * This function does not give you any degree of control over the order -- any
8323  * reorderering is allowed.  If more control is needed, you should probably
8324  * handle drag and drop manually.
8325  **/
8326 void
8327 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
8328                                gboolean     reorderable)
8329 {
8330   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8331
8332   reorderable = reorderable != FALSE;
8333
8334   if (tree_view->priv->reorderable == reorderable)
8335     return;
8336
8337   tree_view->priv->reorderable = reorderable;
8338
8339   if (reorderable)
8340     {
8341       gtk_tree_view_enable_model_drag_source (tree_view,
8342                                               GDK_BUTTON1_MASK,
8343                                               row_targets,
8344                                               G_N_ELEMENTS (row_targets),
8345                                               GDK_ACTION_MOVE);
8346       gtk_tree_view_enable_model_drag_dest (tree_view,
8347                                             row_targets,
8348                                             G_N_ELEMENTS (row_targets),
8349                                             GDK_ACTION_MOVE);
8350     }
8351   else
8352     {
8353       gtk_tree_view_unset_rows_drag_source (tree_view);
8354       gtk_tree_view_unset_rows_drag_dest (tree_view);
8355     }
8356
8357   g_object_notify (G_OBJECT (tree_view), "reorderable");
8358 }
8359
8360 static void
8361 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
8362                                GtkTreePath     *path,
8363                                gboolean         clear_and_select)
8364 {
8365   GtkRBTree *tree = NULL;
8366   GtkRBNode *node = NULL;
8367   GdkModifierType state = 0;
8368
8369   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8370     {
8371       GtkTreePath *cursor_path;
8372       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8373       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
8374       gtk_tree_path_free (cursor_path);
8375     }
8376
8377   gtk_tree_row_reference_free (tree_view->priv->cursor);
8378   gtk_get_current_event_state (&state);
8379
8380   tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
8381                                                               tree_view->priv->model,
8382                                                               path);
8383   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
8384   if (tree != NULL)
8385     {
8386       if (clear_and_select && !((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK))
8387         _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
8388                                                   node, tree, path,
8389                                                   state);
8390       gtk_tree_view_clamp_node_visible (tree_view, tree, node);
8391       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8392     }
8393
8394   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
8395 }
8396
8397 /**
8398  * gtk_tree_view_get_cursor:
8399  * @tree_view: A #GtkTreeView
8400  * @path: A pointer to be filled with the current cursor path, or %NULL
8401  * @focus_column: A pointer to be filled with the current focus column, or %NULL
8402  *
8403  * Fills in @path and @focus_column with the current path and focus column.  If
8404  * the cursor isn't currently set, then *@path will be %NULL.  If no column
8405  * currently has focus, then *@focus_column will be %NULL.
8406  **/
8407 void
8408 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
8409                           GtkTreePath       **path,
8410                           GtkTreeViewColumn **focus_column)
8411 {
8412   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8413
8414   if (path)
8415     {
8416       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8417         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8418       else
8419         *path = NULL;
8420     }
8421
8422   if (focus_column)
8423     {
8424       *focus_column = tree_view->priv->focus_column;
8425     }
8426 }
8427
8428 /**
8429  * gtk_tree_view_set_cursor:
8430  * @tree_view: A #GtkTreeView
8431  * @path: A #GtkTreePath
8432  * @focus_column: A #GtkTreeViewColumn, or %NULL
8433  * @start_editing: %TRUE if the specified cell should start being edited.
8434  *
8435  * Sets the current keyboard focus to be at @path, and selects it.  This is
8436  * useful when you want to focus the user's attention on a particular row.  If
8437  * @column is not %NULL, then focus is given to the column specified by it.
8438  * Additionally, if @column is specified, and @start_editing is %TRUE, then
8439  * editing should be started in the specified cell.  This function is often
8440  * followed by @gtk_widget_grab_focus (@tree_view) in order to give keyboard
8441  * focus to the widget.  Please note that editing can only happen when the
8442  * widget is realized.
8443  **/
8444 void
8445 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
8446                           GtkTreePath       *path,
8447                           GtkTreeViewColumn *focus_column,
8448                           gboolean           start_editing)
8449 {
8450   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8451   g_return_if_fail (path != NULL);
8452   if (focus_column)
8453     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
8454
8455   gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
8456
8457   if (focus_column && focus_column->visible)
8458     {
8459       GList *list;
8460       gboolean column_in_tree = FALSE;
8461
8462       for (list = tree_view->priv->columns; list; list = list->next)
8463         if (list->data == focus_column)
8464           {
8465             column_in_tree = TRUE;
8466             break;
8467           }
8468       g_return_if_fail (column_in_tree);
8469       tree_view->priv->focus_column = focus_column;
8470       if (start_editing)
8471         gtk_tree_view_start_editing (tree_view, path);
8472     }
8473 }
8474
8475
8476 /**
8477  * gtk_tree_view_get_bin_window:
8478  * @tree_view: A #GtkTreeView
8479  * 
8480  * Returns the window that @tree_view renders to.  This is used primarily to
8481  * compare to <literal>event->window</literal> to confirm that the event on
8482  * @tree_view is on the right window.
8483  * 
8484  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
8485  **/
8486 GdkWindow *
8487 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
8488 {
8489   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
8490
8491   return tree_view->priv->bin_window;
8492 }
8493
8494 /**
8495  * gtk_tree_view_get_path_at_pos:
8496  * @tree_view: A #GtkTreeView.
8497  * @x: The x position to be identified.
8498  * @y: The y position to be identified.
8499  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
8500  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
8501  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
8502  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
8503  *
8504  * Finds the path at the point (@x, @y), relative to widget coordinates.  That
8505  * is, @x and @y are relative to an events coordinates. @x and @y must come
8506  * from an event on the @tree_view only where event->window ==
8507  * gtk_tree_view_get_bin (). It is primarily for things like popup menus.
8508  * If @path is non-%NULL, then it will be filled with the #GtkTreePath at that
8509  * point.  This path should be freed with gtk_tree_path_free().  If @column
8510  * is non-%NULL, then it will be filled with the column at that point.
8511  * @cell_x and @cell_y return the coordinates relative to the cell background
8512  * (i.e. the @background_area passed to gtk_cell_renderer_render()).  This
8513  * function is only meaningful if @tree_view is realized.
8514  *
8515  * Return value: %TRUE if a row exists at that coordinate.
8516  **/
8517 gboolean
8518 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
8519                                gint                x,
8520                                gint                y,
8521                                GtkTreePath       **path,
8522                                GtkTreeViewColumn **column,
8523                                gint               *cell_x,
8524                                gint               *cell_y)
8525 {
8526   GtkRBTree *tree;
8527   GtkRBNode *node;
8528   gint y_offset;
8529
8530   g_return_val_if_fail (tree_view != NULL, FALSE);
8531   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
8532
8533   if (path)
8534     *path = NULL;
8535   if (column)
8536     *column = NULL;
8537
8538   if (tree_view->priv->tree == NULL)
8539     return FALSE;
8540
8541   if (x > tree_view->priv->hadjustment->page_size)
8542     return FALSE;
8543
8544   if (x < 0 || y < 0)
8545     return FALSE;
8546
8547   if (column || cell_x)
8548     {
8549       GtkTreeViewColumn *tmp_column;
8550       GtkTreeViewColumn *last_column = NULL;
8551       GList *list;
8552       gint remaining_x = x;
8553       gboolean found = FALSE;
8554
8555       for (list = tree_view->priv->columns; list; list = list->next)
8556         {
8557           tmp_column = list->data;
8558
8559           if (tmp_column->visible == FALSE)
8560             continue;
8561
8562           last_column = tmp_column;
8563           if (remaining_x <= tmp_column->width)
8564             {
8565               found = TRUE;
8566
8567               if (column)
8568                 *column = tmp_column;
8569
8570               if (cell_x)
8571                 *cell_x = remaining_x;
8572
8573               break;
8574             }
8575           remaining_x -= tmp_column->width;
8576         }
8577
8578       if (!found)
8579         {
8580           if (column)
8581             *column = last_column;
8582
8583           if (cell_x)
8584             *cell_x = last_column->width + remaining_x;
8585         }
8586     }
8587
8588   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
8589                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
8590                                       &tree, &node);
8591
8592   if (tree == NULL)
8593     return FALSE;
8594
8595   if (cell_y)
8596     *cell_y = y_offset;
8597
8598   if (path)
8599     *path = _gtk_tree_view_find_path (tree_view, tree, node);
8600
8601   return TRUE;
8602 }
8603
8604
8605 /**
8606  * gtk_tree_view_get_cell_area:
8607  * @tree_view: a #GtkTreeView
8608  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
8609  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
8610  * @rect: rectangle to fill with cell rect
8611  *
8612  * Fills the bounding rectangle in tree window coordinates for the cell at the
8613  * row specified by @path and the column specified by @column.  If @path is
8614  * %NULL, or points to a path not currently displayed, the @y and @height fields
8615  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
8616  * fields will be filled with 0.  The sum of all cell rects does not cover the
8617  * entire tree; there are extra pixels in between rows, for example. The
8618  * returned rectangle is equivalent to the @cell_area passed to
8619  * gtk_cell_renderer_render().  This function is only valid if #tree_view is
8620  * realized.
8621  **/
8622 void
8623 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
8624                              GtkTreePath        *path,
8625                              GtkTreeViewColumn  *column,
8626                              GdkRectangle       *rect)
8627 {
8628   GtkRBTree *tree = NULL;
8629   GtkRBNode *node = NULL;
8630   gint vertical_separator;
8631   gint horizontal_separator;
8632
8633   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8634   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
8635   g_return_if_fail (rect != NULL);
8636   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
8637   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
8638
8639   gtk_widget_style_get (GTK_WIDGET (tree_view),
8640                         "vertical_separator", &vertical_separator,
8641                         "horizontal_separator", &horizontal_separator,
8642                         NULL);
8643
8644   rect->x = 0;
8645   rect->y = 0;
8646   rect->width = 0;
8647   rect->height = 0;
8648
8649   if (column)
8650     {
8651       rect->x = column->button->allocation.x + horizontal_separator/2;
8652       rect->width = column->button->allocation.width - horizontal_separator;
8653     }
8654
8655   if (path)
8656     {
8657       /* Get vertical coords */
8658       if (_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
8659           tree != NULL)
8660         return;
8661
8662       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
8663       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
8664
8665       if (gtk_tree_view_is_expander_column (tree_view, column) &&
8666           TREE_VIEW_DRAW_EXPANDERS (tree_view))
8667         {
8668           gint depth = gtk_tree_path_get_depth (path) - 1;
8669
8670           rect->x += depth * tree_view->priv->expander_size;
8671           rect->width -= depth * tree_view->priv->expander_size;
8672           rect->width = MAX (rect->width, 0);
8673         }
8674     }
8675 }
8676
8677 /**
8678  * gtk_tree_view_get_background_area:
8679  * @tree_view: a #GtkTreeView
8680  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
8681  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
8682  * @rect: rectangle to fill with cell background rect
8683  *
8684  * Fills the bounding rectangle in tree window coordinates for the cell at the
8685  * row specified by @path and the column specified by @column.  If @path is
8686  * %NULL, or points to a node not found in the tree, the @y and @height fields of
8687  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
8688  * fields will be filled with 0.  The returned rectangle is equivalent to the
8689  * @background_area passed to gtk_cell_renderer_render().  These background
8690  * areas tile to cover the entire tree window (except for the area used for
8691  * header buttons). Contrast with the @cell_area, returned by
8692  * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
8693  * surrounding borders and the tree expander area.
8694  *
8695  **/
8696 void
8697 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
8698                                    GtkTreePath        *path,
8699                                    GtkTreeViewColumn  *column,
8700                                    GdkRectangle       *rect)
8701 {
8702   GtkRBTree *tree = NULL;
8703   GtkRBNode *node = NULL;
8704
8705   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8706   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
8707   g_return_if_fail (rect != NULL);
8708
8709   rect->x = 0;
8710   rect->y = 0;
8711   rect->width = 0;
8712   rect->height = 0;
8713
8714   if (path)
8715     {
8716       /* Get vertical coords */
8717
8718       if (_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
8719           tree != NULL)
8720         return;
8721
8722       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
8723
8724       rect->height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
8725     }
8726
8727   if (column)
8728     {
8729       gint x2 = 0;
8730
8731       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
8732       rect->width = x2 - rect->x;
8733     }
8734 }
8735
8736 /**
8737  * gtk_tree_view_get_visible_rect:
8738  * @tree_view: a #GtkTreeView
8739  * @visible_rect: rectangle to fill
8740  *
8741  * Fills @visible_rect with the currently-visible region of the
8742  * buffer, in tree coordinates. Convert to widget coordinates with
8743  * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
8744  * 0,0 for row 0 of the tree, and cover the entire scrollable area of
8745  * the tree.
8746  **/
8747 void
8748 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
8749                                 GdkRectangle *visible_rect)
8750 {
8751   GtkWidget *widget;
8752
8753   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8754
8755   widget = GTK_WIDGET (tree_view);
8756
8757   if (visible_rect)
8758     {
8759       visible_rect->x = tree_view->priv->hadjustment->value;
8760       visible_rect->y = tree_view->priv->vadjustment->value;
8761       visible_rect->width = widget->allocation.width;
8762       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
8763     }
8764 }
8765
8766 /**
8767  * gtk_tree_view_widget_to_tree_coords:
8768  * @tree_view: a #GtkTreeView
8769  * @wx: widget X coordinate
8770  * @wy: widget Y coordinate
8771  * @tx: return location for tree X coordinate
8772  * @ty: return location for tree Y coordinate
8773  *
8774  * Converts widget coordinates to coordinates for the
8775  * tree window (the full scrollable area of the tree).
8776  *
8777  **/
8778 void
8779 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
8780                                      gint         wx,
8781                                      gint         wy,
8782                                      gint        *tx,
8783                                      gint        *ty)
8784 {
8785   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8786
8787   if (tx)
8788     *tx = wx + tree_view->priv->hadjustment->value;
8789   if (ty)
8790     *ty = wy + tree_view->priv->dy - TREE_VIEW_HEADER_HEIGHT (tree_view);
8791 }
8792
8793 /**
8794  * gtk_tree_view_tree_to_widget_coords:
8795  * @tree_view: a #GtkTreeView
8796  * @tx: tree X coordinate
8797  * @ty: tree Y coordinate
8798  * @wx: return location for widget X coordinate
8799  * @wy: return location for widget Y coordinate
8800  *
8801  * Converts tree coordinates (coordinates in full scrollable area of the tree)
8802  * to widget coordinates.
8803  *
8804  **/
8805 void
8806 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
8807                                      gint         tx,
8808                                      gint         ty,
8809                                      gint        *wx,
8810                                      gint        *wy)
8811 {
8812   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8813
8814   if (wx)
8815     *wx = tx - tree_view->priv->hadjustment->value;
8816   if (wy)
8817     *wy = ty - tree_view->priv->dy + TREE_VIEW_HEADER_HEIGHT (tree_view);
8818 }
8819
8820 static void
8821 unset_reorderable (GtkTreeView *tree_view)
8822 {
8823   if (tree_view->priv->reorderable)
8824     {
8825       tree_view->priv->reorderable = FALSE;
8826       g_object_notify (G_OBJECT (tree_view), "reorderable");
8827     }
8828 }
8829
8830 void
8831 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
8832                                         GdkModifierType           start_button_mask,
8833                                         const GtkTargetEntry     *targets,
8834                                         gint                      n_targets,
8835                                         GdkDragAction             actions)
8836 {
8837   TreeViewDragInfo *di;
8838
8839   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8840
8841   di = ensure_info (tree_view);
8842   clear_source_info (di);
8843
8844   di->start_button_mask = start_button_mask;
8845   di->source_target_list = gtk_target_list_new (targets, n_targets);
8846   di->source_actions = actions;
8847
8848   di->source_set = TRUE;
8849
8850   unset_reorderable (tree_view);
8851 }
8852
8853 void
8854 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
8855                                       const GtkTargetEntry     *targets,
8856                                       gint                      n_targets,
8857                                       GdkDragAction             actions)
8858 {
8859   TreeViewDragInfo *di;
8860
8861   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8862
8863   gtk_drag_dest_set (GTK_WIDGET (tree_view),
8864                      0,
8865                      NULL,
8866                      0,
8867                      actions);
8868
8869   di = ensure_info (tree_view);
8870   clear_dest_info (di);
8871
8872   if (targets)
8873     di->dest_target_list = gtk_target_list_new (targets, n_targets);
8874
8875   di->dest_set = TRUE;
8876
8877   unset_reorderable (tree_view);
8878 }
8879
8880 void
8881 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
8882 {
8883   TreeViewDragInfo *di;
8884
8885   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8886
8887   di = get_info (tree_view);
8888
8889   if (di)
8890     {
8891       if (di->source_set)
8892         {
8893           clear_source_info (di);
8894           di->source_set = FALSE;
8895         }
8896
8897       if (!di->dest_set && !di->source_set)
8898         remove_info (tree_view);
8899     }
8900   
8901   unset_reorderable (tree_view);
8902 }
8903
8904 void
8905 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
8906 {
8907   TreeViewDragInfo *di;
8908
8909   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8910
8911   di = get_info (tree_view);
8912
8913   if (di)
8914     {
8915       if (di->dest_set)
8916         {
8917           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
8918           clear_dest_info (di);
8919           di->dest_set = FALSE;
8920         }
8921
8922       if (!di->dest_set && !di->source_set)
8923         remove_info (tree_view);
8924     }
8925
8926   unset_reorderable (tree_view);
8927 }
8928
8929 void
8930 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
8931                                  GtkTreePath            *path,
8932                                  GtkTreeViewDropPosition pos)
8933 {
8934   GtkTreePath *current_dest;
8935   /* Note; this function is exported to allow a custom DND
8936    * implementation, so it can't touch TreeViewDragInfo
8937    */
8938
8939   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8940
8941   current_dest = NULL;
8942
8943   if (tree_view->priv->drag_dest_row)
8944     current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
8945
8946   if (tree_view->priv->drag_dest_row)
8947     gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
8948
8949   tree_view->priv->drag_dest_pos = pos;
8950
8951   if (path)
8952     {
8953       tree_view->priv->drag_dest_row =
8954         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
8955       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
8956     }
8957   else
8958     tree_view->priv->drag_dest_row = NULL;
8959
8960   if (current_dest)
8961     {
8962       GtkRBTree *tree, *new_tree;
8963       GtkRBNode *node, *new_node;
8964
8965       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
8966       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8967
8968       if (tree && node)
8969         {
8970           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
8971           if (new_tree && new_node)
8972             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
8973
8974           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
8975           if (new_tree && new_node)
8976             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
8977         }
8978     }
8979 }
8980
8981 void
8982 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
8983                                  GtkTreePath             **path,
8984                                  GtkTreeViewDropPosition  *pos)
8985 {
8986   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8987
8988   if (path)
8989     {
8990       if (tree_view->priv->drag_dest_row)
8991         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
8992       else
8993         *path = NULL;
8994     }
8995
8996   if (pos)
8997     *pos = tree_view->priv->drag_dest_pos;
8998 }
8999
9000 gboolean
9001 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
9002                                    gint                     drag_x,
9003                                    gint                     drag_y,
9004                                    GtkTreePath            **path,
9005                                    GtkTreeViewDropPosition *pos)
9006 {
9007   gint cell_y;
9008   gdouble offset_into_row;
9009   gdouble quarter;
9010   GdkRectangle cell;
9011   GtkTreeViewColumn *column = NULL;
9012   GtkTreePath *tmp_path = NULL;
9013
9014   /* Note; this function is exported to allow a custom DND
9015    * implementation, so it can't touch TreeViewDragInfo
9016    */
9017
9018   g_return_val_if_fail (tree_view != NULL, FALSE);
9019   g_return_val_if_fail (drag_x >= 0, FALSE);
9020   g_return_val_if_fail (drag_y >= 0, FALSE);
9021   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
9022
9023
9024   if (path)
9025     *path = NULL;
9026
9027   if (tree_view->priv->tree == NULL)
9028     return FALSE;
9029
9030   /* If in the top quarter of a row, we drop before that row; if
9031    * in the bottom quarter, drop after that row; if in the middle,
9032    * and the row has children, drop into the row.
9033    */
9034
9035   if (!gtk_tree_view_get_path_at_pos (tree_view,
9036                                       drag_x,
9037                                       drag_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
9038                                       &tmp_path,
9039                                       &column,
9040                                       NULL,
9041                                       &cell_y))
9042     return FALSE;
9043
9044   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
9045                                      &cell);
9046
9047   offset_into_row = cell_y;
9048
9049   if (path)
9050     *path = tmp_path;
9051   else
9052     gtk_tree_path_free (tmp_path);
9053
9054   tmp_path = NULL;
9055
9056   quarter = cell.height / 4.0;
9057
9058   if (pos)
9059     {
9060       if (offset_into_row < quarter)
9061         {
9062           *pos = GTK_TREE_VIEW_DROP_BEFORE;
9063         }
9064       else if (offset_into_row < quarter * 2)
9065         {
9066           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
9067         }
9068       else if (offset_into_row < quarter * 3)
9069         {
9070           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
9071         }
9072       else
9073         {
9074           *pos = GTK_TREE_VIEW_DROP_AFTER;
9075         }
9076     }
9077
9078   return TRUE;
9079 }
9080
9081
9082
9083 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
9084 /**
9085  * gtk_tree_view_create_row_drag_icon:
9086  * @tree_view: a #GtkTreeView
9087  * @path: a #GtkTreePath in @tree_view
9088  *
9089  * Creates a #GdkPixmap representation of the row at @path.  This image is used
9090  * for a drag icon.
9091  *
9092  * Return value: a newly-allocated pixmap of the drag icon.
9093  **/
9094 GdkPixmap *
9095 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
9096                                     GtkTreePath  *path)
9097 {
9098   GtkTreeIter   iter;
9099   GtkRBTree    *tree;
9100   GtkRBNode    *node;
9101   gint cell_offset;
9102   GList *list;
9103   GdkRectangle background_area;
9104   GdkRectangle expose_area;
9105   GtkWidget *widget;
9106   gint depth;
9107   /* start drawing inside the black outline */
9108   gint x = 1, y = 1;
9109   GdkDrawable *drawable;
9110   gint bin_window_width;
9111
9112   widget = GTK_WIDGET (tree_view);
9113
9114   depth = gtk_tree_path_get_depth (path);
9115
9116   _gtk_tree_view_find_node (tree_view,
9117                             path,
9118                             &tree,
9119                             &node);
9120
9121   if (tree == NULL)
9122     return NULL;
9123
9124   if (!gtk_tree_model_get_iter (tree_view->priv->model,
9125                                 &iter,
9126                                 path))
9127     return NULL;
9128
9129   cell_offset = x;
9130
9131   background_area.y = y;
9132   background_area.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
9133
9134   gdk_drawable_get_size (tree_view->priv->bin_window,
9135                          &bin_window_width, NULL);
9136
9137   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
9138                              bin_window_width + 2,
9139                              background_area.height + 2,
9140                              -1);
9141
9142   expose_area.x = 0;
9143   expose_area.y = 0;
9144   expose_area.width = bin_window_width + 2;
9145   expose_area.height = background_area.height + 2;
9146
9147   gdk_draw_rectangle (drawable,
9148                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
9149                       TRUE,
9150                       0, 0,
9151                       bin_window_width + 2,
9152                       background_area.height + 2);
9153
9154   for (list = tree_view->priv->columns; list; list = list->next)
9155     {
9156       GtkTreeViewColumn *column = list->data;
9157       GdkRectangle cell_area;
9158       gint vertical_separator;
9159
9160       if (!column->visible)
9161         continue;
9162
9163       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
9164                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
9165                                                node->children?TRUE:FALSE);
9166
9167       background_area.x = cell_offset;
9168       background_area.width = column->width;
9169
9170       cell_area = background_area;
9171
9172       gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
9173       cell_area.y += vertical_separator / 2;
9174       cell_area.height -= vertical_separator;
9175
9176       if (gtk_tree_view_is_expander_column (tree_view, column) &&
9177           TREE_VIEW_DRAW_EXPANDERS(tree_view))
9178         {
9179           cell_area.x += depth * tree_view->priv->expander_size;
9180           cell_area.width -= depth * tree_view->priv->expander_size;
9181         }
9182
9183       if (gtk_tree_view_column_cell_is_visible (column))
9184         gtk_tree_view_column_cell_render (column,
9185                                           drawable,
9186                                           &background_area,
9187                                           &cell_area,
9188                                           &expose_area,
9189                                           0);
9190
9191       cell_offset += column->width;
9192     }
9193
9194   gdk_draw_rectangle (drawable,
9195                       widget->style->black_gc,
9196                       FALSE,
9197                       0, 0,
9198                       bin_window_width + 1,
9199                       background_area.height + 1);
9200
9201   return drawable;
9202 }
9203
9204
9205 /**
9206  * gtk_tree_view_set_destroy_count_func:
9207  * @tree_view: A #GtkTreeView
9208  * @func: Function to be called when a view row is destroyed, or %NULL
9209  * @data: User data to be passed to @func, or %NULL
9210  * @destroy: Destroy notifier for @data, or %NULL
9211  *
9212  * This function should almost never be used.  It is meant for private use by
9213  * ATK for determining the number of visible children that are removed when the
9214  * user collapses a row, or a row is deleted.
9215  **/
9216 void
9217 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
9218                                       GtkTreeDestroyCountFunc  func,
9219                                       gpointer                 data,
9220                                       GtkDestroyNotify         destroy)
9221 {
9222   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9223
9224   if (tree_view->priv->destroy_count_destroy)
9225     (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
9226
9227   tree_view->priv->destroy_count_func = func;
9228   tree_view->priv->destroy_count_data = data;
9229   tree_view->priv->destroy_count_destroy = destroy;
9230 }
9231
9232
9233 /*
9234  * Interactive search
9235  */
9236
9237 /**
9238  * gtk_tree_view_set_enable_search:
9239  * @tree_view: A #GtkTreeView
9240  * @enable_search: %TRUE, if the user can search interactively
9241  *
9242  * If @enable_search is set, then the user can type in text to search through
9243  * the tree interactively.
9244  */
9245 void
9246 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
9247                                  gboolean     enable_search)
9248 {
9249   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9250
9251   enable_search = !!enable_search;
9252   
9253   if (tree_view->priv->enable_search != enable_search)
9254     {
9255        tree_view->priv->enable_search = enable_search;
9256        g_object_notify (G_OBJECT (tree_view), "enable_search");
9257     }
9258 }
9259
9260 /**
9261  * gtk_tree_view_get_enable_search:
9262  * @tree_view: A #GtkTreeView
9263  *
9264  * Returns whether or not the tree allows interactive searching.
9265  *
9266  * Return value: whether or not to let the user search interactively
9267  */
9268 gboolean
9269 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
9270 {
9271   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
9272
9273   return tree_view->priv->enable_search;
9274 }
9275
9276
9277 /**
9278  * gtk_tree_view_get_search_column:
9279  * @tree_view: A #GtkTreeView
9280  *
9281  * Gets the column searched on by the interactive search code.
9282  *
9283  * Return value: the column the interactive search code searches in.
9284  */
9285 gint
9286 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
9287 {
9288   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
9289
9290   return (tree_view->priv->search_column);
9291 }
9292
9293 /**
9294  * gtk_tree_view_set_search_column:
9295  * @tree_view: A #GtkTreeView
9296  * @column: the column to search in
9297  *
9298  * Sets @column as the column where the interactive search code should search
9299  * in.  Additionally, turns on interactive searching.
9300  */
9301 void
9302 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
9303                                  gint         column)
9304 {
9305   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9306   g_return_if_fail (column >= 0);
9307
9308   if (tree_view->priv->search_column == column)
9309     return;
9310
9311   tree_view->priv->search_column = column;
9312   g_object_notify (G_OBJECT (tree_view), "search_column");
9313 }
9314
9315 /**
9316  * gtk_tree_view_search_get_search_equal_func:
9317  * @tree_view: A #GtkTreeView
9318  *
9319  * Returns the compare function currently in use.
9320  *
9321  * Return value: the currently used compare function for the search code.
9322  */
9323
9324 GtkTreeViewSearchEqualFunc
9325 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
9326 {
9327   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
9328
9329   return tree_view->priv->search_equal_func;
9330 }
9331
9332 /**
9333  * gtk_tree_view_set_search_equal_func:
9334  * @tree_view: A #GtkTreeView
9335  * @search_equal_func: the compare function to use during the search
9336  * @search_user_data: user data to pass to @search_equal_func, or %NULL
9337  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
9338  *
9339  * Sets the compare function for the interactive search capabilities.
9340  **/
9341 void
9342 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
9343                                      GtkTreeViewSearchEqualFunc  search_equal_func,
9344                                      gpointer                    search_user_data,
9345                                      GtkDestroyNotify            search_destroy)
9346 {
9347   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9348   g_return_if_fail (search_equal_func !=NULL);
9349
9350   if (tree_view->priv->search_destroy)
9351     (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
9352
9353   tree_view->priv->search_equal_func = search_equal_func;
9354   tree_view->priv->search_user_data = search_user_data;
9355   tree_view->priv->search_destroy = search_destroy;
9356   if (tree_view->priv->search_equal_func == NULL)
9357     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
9358 }
9359
9360 static void
9361 gtk_tree_view_search_dialog_destroy (GtkWidget   *search_dialog,
9362                                      GtkTreeView *tree_view)
9363 {
9364   GtkEntry *entry = (GtkEntry *)(gtk_container_get_children (GTK_CONTAINER (search_dialog)))->data;
9365   gint *selected_iter;
9366
9367   if (entry)
9368     {
9369       GdkEventFocus focus_event;
9370
9371       focus_event.type = GDK_FOCUS_CHANGE;
9372       focus_event.in = FALSE;
9373       gtk_widget_event (GTK_WIDGET (entry), (GdkEvent *) &focus_event);
9374     }
9375
9376   /* remove data from tree_view */
9377   g_object_set_data (G_OBJECT (tree_view), GTK_TREE_VIEW_SEARCH_DIALOG_KEY,
9378                      NULL);
9379
9380   selected_iter = g_object_get_data (G_OBJECT (search_dialog),
9381                                      "gtk-tree-view-selected-iter");
9382   if (selected_iter)
9383     g_free (selected_iter);
9384   g_object_set_data (G_OBJECT (search_dialog), "gtk-tree-view-selected-iter",
9385                      NULL);
9386
9387   gtk_widget_destroy (search_dialog);
9388 }
9389
9390 static void
9391 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
9392                                     GtkWidget   *search_dialog)
9393 {
9394   gint x, y;
9395   gint tree_x, tree_y;
9396   gint tree_width, tree_height;
9397   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
9398   GtkRequisition requisition;
9399
9400   gtk_widget_realize (search_dialog);
9401
9402   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
9403   gdk_window_get_size (tree_window,
9404                        &tree_width,
9405                        &tree_height);
9406   gtk_widget_size_request (search_dialog, &requisition);
9407
9408   if (tree_x + tree_width - requisition.width > gdk_screen_width ())
9409     x = gdk_screen_width () - requisition.width;
9410   else if (tree_x + tree_width - requisition.width < 0)
9411     x = 0;
9412   else
9413     x = tree_x + tree_width - requisition.width;
9414
9415   if (tree_y + tree_height > gdk_screen_height ())
9416     y = gdk_screen_height () - requisition.height;
9417   else if (tree_y + tree_height < 0) /* isn't really possible ... */
9418     y = 0;
9419   else
9420     y = tree_y + tree_height;
9421
9422   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
9423 }
9424
9425 static gboolean
9426 gtk_tree_view_search_delete_event (GtkWidget *widget,
9427                                    GdkEventAny *event,
9428                                    GtkTreeView *tree_view)
9429 {
9430   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9431
9432   gtk_tree_view_search_dialog_destroy (widget, tree_view);
9433
9434   return TRUE;
9435 }
9436
9437 static gboolean
9438 gtk_tree_view_search_button_press_event (GtkWidget *widget,
9439                                          GdkEventButton *event,
9440                                          GtkTreeView *tree_view)
9441 {
9442   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9443
9444   gtk_tree_view_search_dialog_destroy (widget, tree_view);
9445
9446   return TRUE;
9447 }
9448
9449 static gboolean
9450 gtk_tree_view_search_key_press_event (GtkWidget *widget,
9451                                       GdkEventKey *event,
9452                                       GtkTreeView *tree_view)
9453 {
9454   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9455   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
9456
9457   /* close window */
9458   if (event->keyval == GDK_Escape ||
9459       event->keyval == GDK_Return ||
9460       event->keyval == GDK_Tab)
9461     {
9462       gtk_tree_view_search_dialog_destroy (widget, tree_view);
9463       return TRUE;
9464     }
9465
9466   /* select previous matching iter */
9467   if (event->keyval == GDK_Up)
9468     {
9469       gtk_tree_view_search_move (widget, tree_view, TRUE);
9470       return TRUE;
9471     }
9472
9473   /* select next matching iter */
9474   if (event->keyval == GDK_Down)
9475     {
9476       gtk_tree_view_search_move (widget, tree_view, FALSE);
9477       return TRUE;
9478     }
9479
9480   return FALSE;
9481 }
9482
9483 static void
9484 gtk_tree_view_search_move (GtkWidget   *window,
9485                            GtkTreeView *tree_view,
9486                            gboolean     up)
9487 {
9488   gboolean ret;
9489   gint *selected_iter;
9490   gint len;
9491   gint count = 0;
9492   gchar *text;
9493   GtkTreeIter iter;
9494   GtkTreeModel *model;
9495   GtkTreeSelection *selection;
9496
9497   text = g_object_get_data (G_OBJECT (window), "gtk-tree-view-text");
9498   selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
9499
9500   g_return_if_fail (text != NULL);
9501
9502   if (!selected_iter || (up && *selected_iter == 1))
9503     return;
9504
9505   len = strlen (text);
9506
9507   if (len < 1)
9508     return;
9509
9510   model = gtk_tree_view_get_model (tree_view);
9511   selection = gtk_tree_view_get_selection (tree_view);
9512
9513   /* search */
9514   gtk_tree_selection_unselect_all (selection);
9515   gtk_tree_model_get_iter_root (model, &iter);
9516
9517   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
9518                                    &count, up?((*selected_iter) - 1):((*selected_iter + 1)));
9519
9520   if (ret)
9521     {
9522       /* found */
9523       *selected_iter += up?(-1):(1);
9524     }
9525   else
9526     {
9527       /* return to old iter */
9528       count = 0;
9529       gtk_tree_model_get_iter_root (model, &iter);
9530       gtk_tree_view_search_iter (model, selection,
9531                                  &iter, text,
9532                                  &count, *selected_iter);
9533     }
9534 }
9535
9536 static gboolean
9537 gtk_tree_view_search_equal_func (GtkTreeModel *model,
9538                                  gint          column,
9539                                  const gchar  *key,
9540                                  GtkTreeIter  *iter,
9541                                  gpointer      search_data)
9542 {
9543   gboolean retval = TRUE;
9544   gchar *normalized_string;
9545   gchar *normalized_key;
9546   gchar *case_normalized_string;
9547   gchar *case_normalized_key;
9548   GValue value = {0,};
9549   gint key_len;
9550
9551   gtk_tree_model_get_value (model, iter, column, &value);
9552   normalized_string = g_utf8_normalize (g_value_get_string (&value), -1, G_NORMALIZE_ALL);
9553   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
9554   case_normalized_string = g_utf8_casefold (normalized_string, -1);
9555   case_normalized_key = g_utf8_casefold (normalized_key, -1);
9556
9557   key_len = strlen (case_normalized_key);
9558
9559   if (!strncmp (case_normalized_key, case_normalized_string, key_len))
9560     retval = FALSE;
9561
9562   g_value_unset (&value);
9563   g_free (normalized_key);
9564   g_free (normalized_string);
9565   g_free (case_normalized_key);
9566   g_free (case_normalized_string);
9567
9568   return retval;
9569 }
9570
9571 static gboolean
9572 gtk_tree_view_search_iter (GtkTreeModel     *model,
9573                            GtkTreeSelection *selection,
9574                            GtkTreeIter      *iter,
9575                            const gchar      *text,
9576                            gint             *count,
9577                            gint              n)
9578 {
9579   GtkRBTree *tree = NULL;
9580   GtkRBNode *node = NULL;
9581   GtkTreePath *path;
9582
9583   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
9584   GtkTreeViewColumn *column =
9585     gtk_tree_view_get_column (tree_view, tree_view->priv->search_column);
9586
9587   path = gtk_tree_model_get_path (model, iter);
9588   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9589
9590   do
9591     {
9592       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
9593         {
9594           (*count)++;
9595           if (*count == n)
9596             {
9597               gtk_tree_selection_select_iter (selection, iter);
9598               gtk_tree_view_scroll_to_cell (tree_view, path, column,
9599                                             TRUE, 0.5, 0.5);
9600               gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
9601
9602               if (path)
9603                 gtk_tree_path_free (path);
9604
9605               return TRUE;
9606             }
9607         }
9608
9609       if (node->children)
9610         {
9611           gboolean has_child;
9612           GtkTreeIter tmp;
9613
9614           tree = node->children;
9615           node = tree->root;
9616
9617           while (node->left != tree->nil)
9618             node = node->left;
9619
9620           tmp = *iter;
9621           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
9622           gtk_tree_path_down (path);
9623
9624           /* sanity check */
9625           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
9626         }
9627       else
9628         {
9629           gboolean done = FALSE;
9630
9631           do
9632             {
9633               node = _gtk_rbtree_next (tree, node);
9634
9635               if (node)
9636                 {
9637                   gboolean has_next;
9638
9639                   has_next = gtk_tree_model_iter_next (model, iter);
9640
9641                   done = TRUE;
9642                   gtk_tree_path_next (path);
9643
9644                   /* sanity check */
9645                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
9646                 }
9647               else
9648                 {
9649                   gboolean has_parent;
9650                   GtkTreeIter tmp_iter = *iter;
9651
9652                   node = tree->parent_node;
9653                   tree = tree->parent_tree;
9654
9655                   if (!tree)
9656                     {
9657                       if (path)
9658                         gtk_tree_path_free (path);
9659
9660                       /* we've run out of tree, done with this func */
9661                       return FALSE;
9662                     }
9663
9664                   has_parent = gtk_tree_model_iter_parent (model,
9665                                                            iter,
9666                                                            &tmp_iter);
9667                   gtk_tree_path_up (path);
9668
9669                   /* sanity check */
9670                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
9671                 }
9672             }
9673           while (!done);
9674         }
9675     }
9676   while (1);
9677
9678   if (path)
9679     gtk_tree_path_free (path);
9680
9681   return FALSE;
9682 }
9683
9684 static void
9685 gtk_tree_view_search_init (GtkWidget   *entry,
9686                            GtkTreeView *tree_view)
9687 {
9688   gint ret;
9689   gint *selected_iter;
9690   gint len;
9691   gint count = 0;
9692   const gchar *text;
9693   GtkWidget *window;
9694   GtkTreeIter iter;
9695   GtkTreeModel *model;
9696   GtkTreeSelection *selection;
9697
9698   g_return_if_fail (GTK_IS_ENTRY (entry));
9699   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9700
9701   window = gtk_widget_get_parent (entry);
9702   text = gtk_entry_get_text (GTK_ENTRY (entry));
9703   len = strlen (text);
9704   model = gtk_tree_view_get_model (tree_view);
9705   selection = gtk_tree_view_get_selection (tree_view);
9706
9707   /* search */
9708   gtk_tree_selection_unselect_all (selection);
9709   selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
9710   if (selected_iter)
9711     g_free (selected_iter);
9712   g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter", NULL);
9713
9714   if (len < 1)
9715     return;
9716
9717   gtk_tree_model_get_iter_root (model, &iter);
9718
9719   ret = gtk_tree_view_search_iter (model, selection,
9720                                    &iter, text,
9721                                    &count, 1);
9722
9723   if (ret)
9724     {
9725       selected_iter = g_malloc (sizeof (int));
9726       *selected_iter = 1;
9727       g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter",
9728                          selected_iter);
9729     }
9730 }
9731
9732 static void
9733 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
9734                              GtkTreeView     *tree_view)
9735 {
9736   if (tree_view->priv->edited_column == NULL)
9737     return;
9738
9739   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
9740   tree_view->priv->edited_column = NULL;
9741
9742   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9743
9744   gtk_container_remove (GTK_CONTAINER (tree_view),
9745                         GTK_WIDGET (cell_editable));
9746 }
9747
9748 static gboolean
9749 gtk_tree_view_start_editing (GtkTreeView *tree_view,
9750                              GtkTreePath *cursor_path)
9751 {
9752   GtkTreeIter iter;
9753   GdkRectangle background_area;
9754   GdkRectangle cell_area;
9755   GtkCellEditable *editable_widget = NULL;
9756   gchar *path_string;
9757   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
9758   gint retval = FALSE;
9759   GtkRBTree *cursor_tree;
9760   GtkRBNode *cursor_node;
9761
9762   g_assert (tree_view->priv->focus_column);
9763
9764   if (! GTK_WIDGET_REALIZED (tree_view))
9765     return FALSE;
9766
9767   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
9768       cursor_node == NULL)
9769     return FALSE;
9770
9771   path_string = gtk_tree_path_to_string (cursor_path);
9772   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
9773   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
9774                                            tree_view->priv->model,
9775                                            &iter,
9776                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9777                                            cursor_node->children?TRUE:FALSE);
9778   gtk_tree_view_get_background_area (tree_view,
9779                                      cursor_path,
9780                                      tree_view->priv->focus_column,
9781                                      &background_area);
9782   gtk_tree_view_get_cell_area (tree_view,
9783                                cursor_path,
9784                                tree_view->priv->focus_column,
9785                                &cell_area);
9786   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
9787                                         &editable_widget,
9788                                         NULL,
9789                                         path_string,
9790                                         &background_area,
9791                                         &cell_area,
9792                                         flags))
9793     {
9794       retval = TRUE;
9795       if (editable_widget != NULL)
9796         {
9797           gtk_tree_view_real_start_editing (tree_view,
9798                                             tree_view->priv->focus_column,
9799                                             cursor_path,
9800                                             editable_widget,
9801                                             &cell_area,
9802                                             NULL,
9803                                             flags);
9804         }
9805
9806     }
9807   g_free (path_string);
9808   return retval;
9809 }
9810
9811 static void
9812 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
9813                                   GtkTreeViewColumn *column,
9814                                   GtkTreePath       *path,
9815                                   GtkCellEditable   *cell_editable,
9816                                   GdkRectangle      *cell_area,
9817                                   GdkEvent          *event,
9818                                   guint              flags)
9819 {
9820   tree_view->priv->edited_column = column;
9821   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
9822   gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
9823   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9824   gtk_tree_view_put (tree_view,
9825                      GTK_WIDGET (cell_editable),
9826                      cell_area->x, cell_area->y, cell_area->width, cell_area->height);
9827   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
9828                                    (GdkEvent *)event);
9829   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
9830   g_signal_connect (cell_editable, "remove_widget", G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
9831 }
9832
9833 static void
9834 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
9835                             gboolean     cancel_editing)
9836 {
9837   if (tree_view->priv->edited_column == NULL)
9838     return;
9839
9840   if (! cancel_editing)
9841     gtk_cell_editable_editing_done (tree_view->priv->edited_column->editable_widget);
9842
9843   gtk_cell_editable_remove_widget (tree_view->priv->edited_column->editable_widget);
9844 }