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