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