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