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