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